Skip to content

Commit

Permalink
Added healthcheck code and docs. No unit tests, though.
Browse files Browse the repository at this point in the history
  • Loading branch information
jwhitlark committed Aug 28, 2014
1 parent f5184d4 commit c67fd2d
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## Changes Between 2.2.x and 2.3.0

## Added metrics.health to provide healthchecks

Contributed by Jason Whitlark.

## Added first cut of a Ganglia reporter

Expand Down
22 changes: 22 additions & 0 deletions docs/source/healthchecks.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
HealthChecks
============

``metrics-clojure-healthchecks`` will allow you to define and run healthcheck.

example
-------

An example using the default HealthCheckRegistry, (which is different
from the default-registry).::

(require '[metrics.health.core :as health])
(defhealthcheck "second-check" (fn [] (let [now (.getSeconds (java.util.Date.))]
(if (< now 30)
(health/healthy "%d is less than 30!" now)
(health/unhealthy "%d is more than 30!" now)))))

(health/check second-check)
#_ => #<Result Result{isHealthy=true, message=3 is less than 30!}>

(health/check-all)
#_ => {:healthy [#<UnmodifiableEntry foo=Result{isHealthy=true, message=6 is less than 30!}>]}
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ Table of Contents
reporting
aggregation
ring
healthchecks
contributing
changelog
4 changes: 4 additions & 0 deletions metrics-clojure-health/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(defproject metrics-clojure-health "2.3.0-SNAPSHOT"
:description "Gluing together metrics-clojure and healthchecks."
:dependencies [[metrics-clojure "2.3.0-SNAPSHOT"]
[com.codahale.metrics/metrics-healthchecks "3.0.2"]])
84 changes: 84 additions & 0 deletions metrics-clojure-health/src/metrics/health/core.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
(ns metrics.health.core
(:require [clojure.set :as set]
[metrics.core :refer [default-registry metric-name]]
[metrics.utils :refer [desugared-title]])
(:import clojure.lang.IFn
[com.codahale.metrics MetricRegistry Gauge]
[com.codahale.metrics.health HealthCheck HealthCheck$Result HealthCheckRegistry]))

(def ^{:tag HealthCheckRegistry :doc "Default health check registry used by public API functions when no explicit registry argument is given"}
default-healthcheck-registry
(HealthCheckRegistry.))

(defn healthy
"Returns a healthy result."
([] (HealthCheck$Result/healthy))
([^String message & args]
(HealthCheck$Result/healthy (apply format message args))))

(defn unhealthy
"Returns a unhealthy result."
([^String message & args]
(HealthCheck$Result/unhealthy (apply format message args))))

(defn new-hc
"Wrap a fn to ensure it returns healthy/unhealthy. Any exception or
non-healthy result is considered unhealthy and returned as such."
([^IFn hc-fn] (proxy [HealthCheck] []
(check []
(let [result (hc-fn)]
(if (instance? HealthCheck$Result result)
result
(unhealthy (str "Bad HealthCheck result: " result))))))))

(defn healthcheck-fn
"Create and register a new healthcheck. hc-fn must return
healthy/unhealthy; any other result, (including an exception), will
be considered unhealthy."
([title ^IFn hc-fn]
(healthcheck-fn default-healthcheck-registry title hc-fn))
([^HealthCheckRegistry reg title ^IFn hc-fn]
(let [hc (new-hc hc-fn)]
;; REVIEW: Should this automatically remove a previous check of
;; the same title? (jw 14-08-28)
(.register reg title hc)
hc)))

(defmacro defhealthcheck
"Define a new Healthcheck metric with the given title and a function.
to call to retrieve the value of the Healthcheck.
The title uses some basic desugaring to let you concisely define metrics:
; Define a healthcheck titled \"default.default.foo\" into var foo
(defhealthcheck foo ,,,)
(defhealthcheck \"foo\" ,,,)
; Define a healthcheck titled \"a.b.c\" into var c
(defhealthcheck [a b c] ,,,)
(defhealthcheck [\"a\" \"b\" \"c\"] ,,,)
(defhealthcheck [a \"b\" c] ,,,)
"
([title ^clojure.lang.IFn f]
(let [[s title] (desugared-title title)]
`(def ~s (healthcheck-fn '~title ~f))))
([^HealthCheckRegistry reg title ^clojure.lang.IFn f]
(let [[s title] (desugared-title title)]
`(def ~s (healthcheck-fn ~reg '~title ~f)))))

(defn check
"Run a given HealthCheck."
[^HealthCheck h]
(.check ^HealthCheck h))

(defn check-all
"Returns a map with the keys :healthy & :unhealthy, each containing
the associated checks. Note that the items of each vector are of
type
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry,
but key & val work on it."
([] (check-all default-healthcheck-registry))
([^HealthCheckRegistry reg]
(let [results (.runHealthChecks reg)
group-results (group-by #(.isHealthy ^HealthCheck$Result (val %)) results)]
(set/rename-keys group-results {true :healthy false :unhealthy}))))

0 comments on commit c67fd2d

Please sign in to comment.