The ClojureWerkz Blog

News and updates about ClojureWerkz projects

Metrics-clojure 2.2.0 Is Released

TL;DR

metrics-clojure is a Clojure façade around Coda Hale’s Metrics library, originally developed by Steve Losh.

metrics-clojure is not a ClojureWerkz project but we help maintain it and consider it to be a very valuable library.

Changes Between 2.1.x and 2.2.0

Graphite Extension

metrics.reporters.graphite is a new sub-project that contains a Graphite reporter.

Ring Extension Now Respects User-provided Registry

The Ring extension now respects user-provided registries instead of always using the default one.

Contributed by David Smith.

Bugfixes

  • Fixed metrics.core/default-registry to have a valid reflection hint (no longer causes compile error when used in interop.) Fix planned on 2.1.x as well. Contributed by Tim McCormack.

Full Change Log

metrics-clojure change log is available on GitHub.

About the Author

Michael on behalf of the metrics-clojure Team.

Langohr 3.0.0-rc2 Is Released

TL;DR

Langohr is a small Clojure RabbitMQ client.

3.0 will be a major release that introduces moderate internal changes in the library and some breaking public API refinements.

Changes between Langohr 2.11.x and 3.0.0-rc2

Options as Maps

Functions that take options now require a proper Clojure map instead of pseudo keyword arguments:

1
2
3
4
5
6
7
8
9
10
11
12
# in Langohr 2.x

(lq/declare ch q :durable true)
(lhcons/subscribe ch q (fn [_ _ _])
                        :consumer-tag ctag :handle-cancel-ok (fn [_]))
(lb/publish ch "" q "a message" :mandatory true)

# in Langohr 3.x
(lq/declare ch q {:durable true})
(lhcons/subscribe ch q (fn [_ _ _])
                        {:consumer-tag ctag :handle-cancel-ok (fn [_])})
(lb/publish ch "" q "a message" {:mandatory true})

JDK 8 Compatibility

Langohr test suite now passes on JDK 8 (previously there was 1 failure in recovery test).

GH issue: #54.

Connection Recovery Performed by Java Client

Langohr no longer implements automatic connection recovery of its own. The feature is still there and there should be no behaviour changes but the functionality has now been pushed “upstream” in the Java client, so Langohr now relies on it to do all the work.

There is one public API change: com.novemberain.langohr.Recoverable is gone, langohr.core/on-recovery now uses com.rabbitmq.client.Recoverable instead in its signature.

GH issue: #58.

RabbitMQ Java Client Upgrade

RabbitMQ Java client dependency has been updated to 3.3.5.

Custom Exception Handlers

langohr.core/exception-handler is a function that customizes default exception handler RabbitMQ Java client uses:

1
2
3
4
5
6
(require '[langohr.core :as rmq])

(let [(rmq/exception-handler :handle-consumer-exception-fn (fn [ch ex consumer
                                                               consumer-tag method-name]
                                                             ))]
  )

Valid keys are:

  • :handle-connection-exception-fn
  • :handle-return-listener-exception-fn
  • :handle-flow-listener-exception-fn
  • :handle-confirm-listener-exception-fn
  • :handle-blocked-listener-exception-fn
  • :handle-consumer-exception-fn
  • :handle-connection-recovery-exception-fn
  • :handle-channel-recovery-exception-fn
  • :handle-topology-recovery-exception-fn

GH issue: #47.

langohr.core/version is Removed

langohr.core/version was removed.

Change Log

Langohr change log is available on GitHub.

Langohr is a ClojureWerkz Project

Langohr is part of the group of libraries known as ClojureWerkz, together with

  • Elastisch, a minimalistic well documented Clojure client for ElasticSearch
  • Cassaforte, a Clojure Cassandra client built around CQL 3.0
  • Monger, a Clojure MongoDB client for a more civilized age
  • Neocons, a client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Langohr, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About The Author

Michael on behalf of the ClojureWerkz Team

Elastisch 2.1.0-beta5 Is Released

TL;DR

Elastisch is a battle tested, small but feature rich and well documented Clojure client for ElasticSearch. It supports virtually every Elastic Search feature and has solid documentation.

2.1.0-beta5 is a preview release of Elastisch 2.1.

Changes between Elastisch 2.1.0-beta4 and 2.1.0-beta5

ElasticSearch Native Client Upgrade

Elastisch now depends on ElasticSearch native client version 1.3.x.

Single-Bucket Aggregation Fix in the Native Client

Child aggregations in single-bucket aggregations (i.e. “global”) are no longer silently dropped.

Contributed by Yannick Scherer (StyleFruits).

Full Change Log

Elastisch change log is available on GitHub.

Elastisch is a ClojureWerkz Project

Elastisch is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Monger, a Clojure MongoDB client for a more civilized age
  • Cassaforte, a Clojure Cassandra client
  • Titanium, a Clojure graph library
  • Neocons, a client for the Neo4J REST API
  • Welle, a Riak client with batteries included
  • Quartzite, a powerful scheduling library

and several others. If you like Elastisch, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About the Author

Michael on behalf of the ClojureWerkz Team

Validateur 2.3.1 Is Released

TL;DR

Validateur is a functional validations library inspired by Ruby’s ActiveModel. Validateur 2.3 is a minor feature release.

Changes Between 2.2.0 and 2.3.0

unnest

unnest is a helper function useful for building UIs that validate on the fly. Here’s a basic example. Let’s write some code to render a UI off of a nested map and build up live validation for that map off of component validators. Here are the components:

1
2
3
4
5
6
7
8
(def profile-validator
  (vr/validation-set
   (vr/presence-of #{:first-name :last-name})))

(def secret-validator
  (vr/validation-set
   (vr/length-of :password :within (range 5 15))
   (vr/length-of :phone :is 10)))

And then the composed, user account validator:

1
2
3
4
(def account-validator
  (vr/compose-sets
   (vr/nested :secrets secret-validator)
   (vr/nested :profile profile-validator)))

Next are the “rendering” functions. Imagine that these are input components responsible for validating their input and displaying errors when present. Our “render” phase will just print.

1
2
3
4
5
6
7
8
9
10
11
12
13
(defn render-profile [profile errors]
  (prn "Profile: " profile)
  (prn "Profile Errors: " errors))

(defn render-secrets [secrets errors]
  (prn "Secrets: " secrets)
  (prn "Secret Errors: " errors))

(defn submit-button
  "Renders a submit button that can only submit when no errors are
  present."
  [errors]
  (prn "All Errors: " errors))

The render-account function renders all subcomponents, performs global validation and routes the errors and data where each needs to go:

1
2
3
4
5
6
7
8
9
10
11
12
13
(defn render-account
  "This function accepts an account object, validates the entire thing
  using the subvalidators defined above, then uses unnested to pull
  out specific errors for each component.

  The entire validation error map is passed into submit-button,
  which might only allow a server POST on click of the full error map
  is empty."
  [{:keys [secrets profile] :as account}]
  (let [errors (account-validator account)]
    (render-profile profile (vr/unnest :profile errors))
    (render-secrets secrets (vr/unnest :secrets errors))
    (submit-button errors)))

Let’s see this function in action. Calling render-account with an invalid map triggers a render that shows off a bunch of errors:

1
2
3
4
5
6
7
8
9
10
11
(render-account
   {:secrets {:password "face"
              :phone "703555555512323"}
    :profile {:first-name "Queequeg"}})


"Profile: " {:first-name "Queequeg"}
"Errors: " {[:last-name] #{"can't be blank"}}
"Secrets: " {:password "face", :phone "703555555512323"}
"Errors: " {[:phone] #{"must be 10 characters long"}, [:password] #{"must be from 5 to 14 characters long"}}
"All Errors: " {[:profile :last-name] #{"can't be blank"}, [:secrets :phone] #{"must be 10 characters long"}, [:secrets :password] #{"must be from 5 to 14 characters long"}}

Calling render-account with a valid map prints only the data:

1
2
3
4
5
6
7
8
9
10
11
(render-account
 {:secrets {:password "faceknuckle"
            :phone "7035555555"}
  :profile {:first-name "Queequeg"
            :last-name "Kokovoko"}})

"Profile: " {:last-name "Kokovoko", :first-name "Queequeg"}
"Errors: " {}
"Secrets: " {:password "faceknuckle", :phone "7035555555"}
"Errors: " {}
"All Errors: " {}

nest

nest is a helper function that makes it easy to validate dynamic data that’s not part of the actual map you pass into the validator. For example, say you wanted to validate all user accounts, then build up a map of userid –> validation errors:

1
2
3
4
5
6
7
8
(for [account (get-all-accounts)]
  (vr/nest (:id account)
           (account-validator account)))

{[100 :profile :first-name] "can't be blank"
 [200 :profile :last-name] "can't be blank"
 ;; etc
 }

Full Change Log

Validateur change log is available on GitHub.

Validateur is a ClojureWerkz Project

Validateur is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Monger, a Clojure MongoDB client for a more civilized age
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Cassaforte, a Clojure Cassandra client built around CQL
  • Neocons, a client for the Neo4J REST API
  • Welle, a Riak client with batteries included
  • Quartzite, a powerful scheduling library

and several others. If you like Validateur, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About The Author

Michael on behalf of the ClojureWerkz Team

Mailer 1.2.0 Is Released

TL;DR

ClojureWerkz Mailer is an ActionMailer-inspired mailer library for Clojure.

1.2.0 is a minor feature release.

Changes Between 1.1.0 and 1.2.0

Improved Template Rendering Exceptions

Template rendering exceptions now have a better error message.p

Contributed by Lei.

Mailer is a ClojureWerkz Project

Mailer is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Cassaforte, a Clojure client for Cassandra built around CQL
  • Monger, a Clojure MongoDB client for a more civilized age
  • Welle, a Riak client with batteries included
  • Neocons, a Clojure client for the Neo4J REST API

and several others. If you like Mailer, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About the Author

Michael on behalf of the ClojureWerkz Team.

Validateur 2.2.0 Is Released

TL;DR

Validateur is a functional validations library inspired by Ruby’s ActiveModel. Validateur 2.2 is a minor feature release.

Changes Between 2.1.0 and 2.2.0

nested

nested is a new validator runner for nested attributes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(require '[validateur.validation :refer :all])

(let [v (vr/nested :user (vr/validation-set
                            (vr/presence-of :name)
                            (vr/presence-of :age)))
        extra-nested (vr/nested [:user :profile]
                                (vr/validation-set
                                 (vr/presence-of :age)
                                 (vr/presence-of [:birthday :year])))]
  (v {})
  ;= {[:user :age] #{"can't be blank"}
      [:user :name] #{"can't be blank"}}
  (v {:user {:name "name"}})
  ;= {[:user :age] #{"can't be blank"}}
  (extra-nested {:user {:profile {:age 10
                                  :birthday {:year 2004}}}})
  ;= {}
  (extra-nested {:user {:profile {:age 10}}})
  ;= {[:user :profile :birthday :year] #{"can't be blank"}}

Contributed by Sam Ritchie.

validate-by

validate-by is a new validator function. It returns a function that, when given a map, will validate that the + value of the attribute in that map is one of the given:

1
2
3
4
5
6
(require '[validateur.validation :refer :all])

(validation-set
   (presence-of :name)
   (presence-of :age)
   (validate-by [:user :name] not-empty :message \"Username can't be empty!\"))

Contributed by Sam Ritchie.

Full Change Log

Validateur change log is available on GitHub.

Validateur is a ClojureWerkz Project

Validateur is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Monger, a Clojure MongoDB client for a more civilized age
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Cassaforte, a Clojure Cassandra client built around CQL
  • Neocons, a client for the Neo4J REST API
  • Welle, a Riak client with batteries included
  • Quartzite, a powerful scheduling library

and several others. If you like Validateur, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About The Author

Michael on behalf of the ClojureWerkz Team

Mailer 1.1.0 Is Released

TL;DR

ClojureWerkz Mailer is an ActionMailer-inspired mailer library for Clojure.

1.1.0 is a minor feature release.

Changes Between 1.0.0 and 1.1.0

Support for Alternative Email Bodies

build-email and deliver-email now take extra set of template, data, content-type for alternative email body. This is useful for supplying alternative plain-text body in addition to main HTML body of the message.

1
2
3
(build-email {:from "Joe The Robot", :to ["ops@megacorp.internal" "oncall@megacorp.internal"] :subject "Hello!"}
             "templates/html_hello.mustache" {:name "Joe"} :text/html
             "templates/hello.mustache" {:name "Joe"} :text/plain)

Contributed by Lei.

Mailer is a ClojureWerkz Project

Mailer is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Cassaforte, a Clojure client for Cassandra built around CQL
  • Monger, a Clojure MongoDB client for a more civilized age
  • Welle, a Riak client with batteries included
  • Neocons, a Clojure client for the Neo4J REST API

and several others. If you like Mailer, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About the Author

Michael on behalf of the ClojureWerkz Team.

Quartzite 1.3.0 Is Released

Quartzite is a Clojure DSL on top of the Quartz scheduler.

1.3.0 is a minor release that contains minor improvements and upgrades dependencies.

Changes Between Quartzite 1.2.0 and 1.3.0

Clojure 1.6 by Default

The library now depends on Clojure 1.6.

clj-time upgraded to 0.8.0

clj-time dependency has been upgraded to version 0.8.0.

Changes between Quartzite 1.1.0 and 1.2.0

Clojure 1.3 is No Longer Supported

Quartzite requires Clojure 1.4+ as of this version.

clj-time upgraded to 0.6.0

clj-time dependency has been upgraded to version 0.6.0.

New Functions

  • clojurewerkz.quartzite.scheduler/get-currently-executing-jobs returns a set of currently executing jobs.
  • clojurewerkz.quartzite.scheduler/currently-executing-job? returns true there is a running job for a given key.

Change Log

Quartzite change log is available on GitHub.

Quartzite is a ClojureWerkz Project

Quartzite is part of the group of libraries known as ClojureWerkz, together with

  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Monger, a Clojure MongoDB driver for a more civilized age
  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Welle, a Riak client with batteries included
  • Neocons, a client for the Neo4J REST API

and several others. If you like Quartzite, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

@michaelklishin on behalf of the ClojureWerkz Team

CHash 1.1.0 Is Released

TL;DR

Chash is a Clojure consistent hashing library ported from riak_core.

Changes Between 1.0.x and 1.1.0

Clojure 1.6 by Default

The library now depends on Clojure 1.6.

Change Log

Chash change log is available on GitHub.

Chash is a ClojureWerkz Project

Chash is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Cassaforte, a Clojure Cassandra client built around CQL
  • Monger, a Clojure MongoDB client for a more civilized age
  • Welle, a Riak client with batteries included
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Neocons, a client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Chash, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

Michael on behalf of the ClojureWerkz Team

Metrics-clojure 2.1.1 Is Released

TL;DR

metrics-clojure is a Clojure façade around Coda Hale’s Metrics library, originally developed by Steve Losh.

metrics-clojure is not a ClojureWerkz project but we help maintain it and consider it to be a very valuable library.

Changes Between 2.1.0 and 2.1.1

Ring Extension Now Respects User-provided Registry

The Ring extension now respects user-provided registries instead of always using the default one.

Contributed by David Smith.

Changes Between 2.0.x and 2.1.0

Ring Extension Supports Multiple Registries and Options

It is now possible to use metrics.ring.expose with a custom registry:

1
2
3
(require '[metrics.ring.expose :refer [expose-metrics-as-json]])

(expose-metrics-as-json ring-app "/ops/metrics" registry {:pretty-print? true})

JVM Instrumentation Extension

The project now also has a JVM instrumentation extension that covers:

  • Number of threads and their states
  • GC stats, heap, off heap memory
  • File descriptors

To enable full instrumenting, use

1
2
3
(require '[metrics.jvm.core :refer [instrument-jvm]])

(instrument-jvm metric-registry)

Contributed by John Cowie (ThoughtWorks).

timers/mean Returns Value (Not Rate)

metrics.timers/mean now returns mean value (not rate) of the timer.

Contributed by Steve Miner.

Ring Extension Updated for 2.0

The Ring extension is now updated for Metrics core 2.0 API.

Contributed by John Cowie (ThoughtWorks).

Changes Between 1.1.0 and 2.0.0

Metrics Registries

metrics-clojure 1.x maintained a metrics registry in a dynamic var. This approach makes the library a little easier for beginners but also much harder to use in more sophisticated cases, e.g. in concurrent applications or those that use a Component-like approach to program structure.

As such, metrics-clojure 2.0+ makes metrics registry a required explicit argument to most functions in the API:

1
2
3
4
5
6
7
8
9
10
(require '[metrics.meters :as meters])

;; with 1.x
(meters/rate-mean)
(meters/mark! 10)

;; with 2.0
(let [m (meters/meter ["test" "meters" "test-rate-mean-update-multiple"])]
  (meters/rate-mean m)
  (meters/mark! m 10))

The library maintains a default registry in metrics.core/default-registry which tries to keep the 1.x API as functional as possible but using your own registry is encouraged.

To instantiate a registry, use metrics.core/new-registry:

1
2
3
(require '[metrics.core :as mtr])

(mtr/new-registry)

See GH #19 for discussion.

defgauge Restricted to Functions Only

In metrics-clojure 1.x, metrics.gauges/defgauge could accept a function or a bunch of forms (body). In 2.0, it only accepts a function. This is in part due to the new API structure but also make the API more straightforward and works much better with explicit registry management now advocated by the library.

Nanoseconds Precision in Timers

Metrics 3.0 uses nanoseconds precision in timers.

Upgrade to Metrics 3.0

Metrics 3.0 is now used internally by the library.

Clojure 1.3 No Longer Supported

Clojure 1.3 is no longer supported by the library.

Full Change Log

metrics-clojure change log is available on GitHub.

About the Author

Michael on behalf of the metrics-clojure Team.