Clockwork in a browser extension for Chrome and Firefox devtools, providing tools for debugging and profiling your application. This library is a Clojure backend counterpart for the extension.
There are two parts to clockwork: one is a Ring middleware and another is a couple of macros.
It's initialialized by wrapping your app in clockwork.core/wrap
:
(def app (clockwork.core/wrap my-handler
{:authorized? (fn [req] (user/admin? req))}))
There are a couple of options for the middleware:
:authorized?
- this checks if a current user can access profiling information (by default all requests to localhost are allowed):profile-request?
- this checks if a request should be profiled: skipping static and media data seems logical (by default all authorized requests are profiled, except for requests for clockwork data):prefix
- prefix for all internal Clockwork requests (by default it's/__clockwork/
):store
- store for Clockwork data (by default in-memory, for details see lower)
There are two types of timing information: trace
and timing
.
trace
is a section of your code, where something happens: like request
parsing, or maybe template rendering, etc - it shows up on nested timeline.
Signature: (trace section-name & body)
Example:
(clockwork/trace (str "app " (:uri req))
(my-handler req))
timing
is a call to some (external) resource, like database, cache lookup or
internal http request. It shows in a DB
tab.
Signature: (timing type description & body)
Example:
(defn q [query]
(clockwork/timing "pg" (pr-str query)
(jdbc/query db-conn (query->args query))))
(defn cache-get [key]
(clockwork/timing "cache get" key (.get memcache key)))
Default store is an in-memory one, just holding everything in an atom. Of course, this works well enough only if you have a single application process - and if you have multiple, you have to provide your own. Here is an example of using memcached as a store:
(defrecord CWStore [mc prefix]
clockwork.store/Storage
(save [this id data]
(try (.set mc (str prefix id) 100000 data)
(catch Exception e nil)))
(fetch [this id]
(try (.get mc (str prefix id))
(catch Exception e nil))))