Code Monkey home page Code Monkey logo

metrics-clojure's Introduction

metrics-clojure

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

Installation

Add this to your project.clj's dependencies:

[metrics-clojure "2.10.0"]

Or to your deps.edn's :deps map:

metrics-clojure/metrics-clojure {:mvn/version "2.10.0"}

That's it.

Usage

Read the docs.

Change Log

Right here

More Information

metrics-clojure's People

Contributors

aeronotix avatar davidsmith7 avatar eranharel avatar iamjarvo avatar ieugen avatar ieure avatar joelittlejohn avatar johncowie avatar jwhitlark avatar kumarshantanu avatar malesch avatar matthiasn avatar mgaare avatar michaelklishin avatar micrub avatar miner avatar mnuessler avatar mping avatar neilprosser avatar npetryk avatar paulbellamy avatar pyr avatar ragnard avatar ryfow avatar sjl avatar sunng87 avatar taylorwood avatar timmc-bcov avatar vincentbernat avatar wyegelwel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

metrics-clojure's Issues

2.0 release is missing import for Metric

~/cljproj/metrics-clojure/metrics-clojure-core $ lein test
Exception in thread "main" java.lang.IllegalArgumentException: Unable to resolve classname: Metric, compiling:(metrics/core.clj:23:1)

quick fix in metrics-clojure-core/src/metrics/core.clj

  • (:import [com.codahale.metrics MetricRegistry]))
  • (:import [com.codahale.metrics MetricRegistry Metric]))

Push 1.1.0 to clojars?

I noticed that you created version 1.1.0, but when I tried to use it in a leiningen project it wasn't available. Do you plan on pushing it to an accessible maven repo?

Upgrade to latest dropwizard metrics

The latest dropwizard metrics (4.x.x) removed a lot of clutter, and is now Java 8 based and supports Java 9.
Now that the older (< 8) Java versions are EOL it makes sense to upgrade, and I'll be happy to contribute a patch if it's agreed.

Make `remove-metric` accepts a predicate

Hey!

Would it be possible to make remove-metric accepts a predicate (or remove-all-metrics, or a new remove-metrics). The use case is I am registering metrics for various subsystems and it would be more convenient to remove all the metrics related to the given subsystem at once. I can easily identify them because they share the same group name.

Why `default.default` is added when metric name is string?

Trying to understand metric-name function

(defn ^String metric-name
  [title]
  (if (string? title)
    (MetricRegistry/name "default"
                         ^"[Ljava.lang.String;" (into-array String ["default" ^String title]))
    (MetricRegistry/name
     ^String (first title)
     ^"[Ljava.lang.String;" (into-array String
                                        (if (= 3 (count title))
                                          [(second title) (last title)]
                                          (rest title))))))

https://github.com/sjl/metrics-clojure/blob/master/metrics-clojure-core/src/metrics/core.clj#L19

Why do you need to append default.default if a normal string is provided as the metric name? MetricRegistry/name seems to accept normal string fine without list of strings

JVM metrics have duplicated parts in their names

After adding the JVM metrics in I'm seeing that they've got duplicate parts in their names, as per the following example:

prefix.jvm.attribute.attribute.uptime 9494 1407747104
prefix.jvm.file.file 0.01 1407747104
prefix.jvm.gc.gc.PS-Scavenge.time 72 1407747104
prefix.jvm.memory.memory.total.used 208921648 1407747104
prefix.jvm.thread.thread.blocked.count 0 1407747104

This looks like it's down to the way the Metrics library used to have three parts (I think they were called group, class and scope) and metrics-clojure picks out the first, second and last to form the three. In the case of a two item array (which the JVM metrics use) the second of those items is repeated.

Switching the JVM metrics name arrays to a string (e.g. jvm.attribute) results in the following:

prefix.default.default.jvm.attribute.uptime 9478 1407748160
prefix.default.default.jvm.file 0.01 1407748160
prefix.default.default.jvm.gc.PS-MarkSweep.count 0 1407748160
prefix.default.default.jvm.memory.heap.committed 376963072 1407748160
prefix.default.default.jvm.thread.blocked.count 0 1407748160

... because we're filling in the missing parts with default instead.

We could add another condition in the metric-name function in core.clj which spots that the non-string path handles an array with three items differently from an array with some other number of items.

Alternatively, we could switch to using the newer Metrics 3 style MetricRegistry.name(String, String...) method instead and just give the title as provided by the user.

The first approach results in more code, the second has the possibility of changing the names of people's metrics without them choosing it.

I'm happy to work up a pull-request with whichever approach you think is best. I personally prefer keeping my metric paths as short as possible and like that Metrics 3 got rid of the 'every metric name must have three parts' idea. The second approach means people can just provide a dotted string for their metric names.

Timers documentation says milliseconds, but code returns nanoseconds

The Reading section of the timers documentation Says that the functions return values in milliseconds, but they appear to actually return values in nanoseconds.

What is correct? I'll submit a pull request on the code or documentation, but I need to know how it's supposed to work first.

user=> (require '[metrics.timers :as timers])
nil
user=> (timers/time! (timers/timer "foo") (Thread/sleep 10))
nil
user=> (timers/percentiles (timers/timer "foo"))
{0.75 1.0436789E7, 0.95 1.0436789E7, 0.99 1.0436789E7, 0.999 1.0436789E7, 1.0 1.0436789E7}
user=> (->> (timers/percentiles (timers/timer "foo")) (map (fn [[k v]] [k (/ v 1000000)])))
([0.75 10.436789] [0.95 10.436789] [0.99 10.436789] [0.999 10.436789] [1.0 10.436789])

user=> (timers/smallest (timers/timer "foo"))
10436789
user=> (timers/mean (timers/timer "foo"))
1.0436789E7
user=> (/ (timers/mean (timers/timer "foo")) 1000000)
10.436789

Document API conventions better

In 2.0, we now have an API convention: most (if not all) functions that define/return metrics accept a metrics registry as their first argument, or it can be omitted, then metrics.core/default-registry will be used. This is kind of reflected in the docs now
but needs to be made clearer.

ClassNotFound when using methods from MetricRegistry

When trying to use the .meter method on the default registry (In 2.2.0-beta1), I was getting classnotfound errors.

i.e.

(.meter metrics/default-registry "a.b.c") 

would not compile. However, when I added a type hint, that fixed the problem

;; added to ns form
(:import [com.codahale.metrics MetricRegistry])

(.meter ^MetricRegistry metrics/default-registry "a.b.c")

works just fine.

I'm not sure if this is a bug, a misunderstanding on my part, or just something that needs to be documented.

GraphiteReporter cannot recover from lost connection

It looks like a network hiccup can cause GraphiteReporter to get into a bad state. I can consistently get the following pair of errors (which constantly repeat) by interrupting the network connection. I don't see a bug report upstream in dropwizard/metrics, but I'm not sure if this is a problem with metrics-clojure or dropwizard/metrics.

2015-02-17 14:18:53,562 WARN  com.codahale.metrics.graphite.GraphiteReporter: Unable to report to Graphite
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
        at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
        at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:282)
        at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
        at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
        at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
        at java.io.BufferedWriter.write(BufferedWriter.java:230)
        at java.io.Writer.write(Writer.java:157)
        at com.codahale.metrics.graphite.Graphite.send(Graphite.java:130)
        at com.codahale.metrics.graphite.GraphiteReporter.reportMetered(GraphiteReporter.java:234)
        at com.codahale.metrics.graphite.GraphiteReporter.report(GraphiteReporter.java:170)
        at com.codahale.metrics.ScheduledReporter.report(ScheduledReporter.java:162)
        at com.codahale.metrics.ScheduledReporter$1.run(ScheduledReporter.java:117)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
2015-02-17 14:18:53,562 WARN  com.codahale.metrics.graphite.GraphiteReporter: Error closing Graphite
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
        at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
        at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:282)
        at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
        at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
        at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
        at java.io.BufferedWriter.write(BufferedWriter.java:230)
        at java.io.Writer.write(Writer.java:157)
        at com.codahale.metrics.graphite.Graphite.send(Graphite.java:130)
        at com.codahale.metrics.graphite.GraphiteReporter.reportMetered(GraphiteReporter.java:234)
        at com.codahale.metrics.graphite.GraphiteReporter.report(GraphiteReporter.java:170)
        at com.codahale.metrics.ScheduledReporter.report(ScheduledReporter.java:162)
        at com.codahale.metrics.ScheduledReporter$1.run(ScheduledReporter.java:117)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)

Make it possible to add password protection to expose-metrics-as-json

The documentation for the ring extras says "WARNING: this URL will not be protected by a username or password in any way (yet), so if you have sensitive metrics you might want to think twice about using it (or protect it yourself)."

IMHO, the easiest way for adding password protection myself would be to add a route to composure that reads like

(GET "/metrics" [] (with-admin-privileges metrics-json))

instead of expose-metrics-as-json (where with-admin-privileges would ensure protection). But for this, "metrics-json" from the ring extras would have to be public. Can you make this method public so I can define the routes myself? Or did I misunderstand / miss something here?

code still uses com.codahale.metrics package name not io.dropwizard.metrics

Maybe I am missing something, but if sjl/metrics-clojure is using 3.1 version of metrics now with the 2.6.0 release, then the package names should be (:import [io.dropwizard.metrics MetricRegistry]) not (:import [com.codahale.metrics MetricsRegistry])

(ns metrics.core
(:import [com.codahale.metrics MetricRegistry Metric]))

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

(defn ^com.codahale.metrics.MetricRegistry new-registry
)

https://github.com/dropwizard/metrics/blob/master/metrics-core/src/main/java/io/dropwizard/metrics/MetricRegistry.java

Exception handling in Graphite reporter

Hi!

I've recently started using metrics-clojure, thank you for great work!

I have a question - is it possible (somehow) to provide exception handler to Graphite reporter, so that in cases when Graphite/Carbon server for some reason is unavailable, exception messages are redirected t o some file etc. instead of being printed to standard output?

Thanks,
Vitaliy.

Transfer project to clj-commons ?

Hello @michaelklishin ,

Are you open to transferring this project to clj-commons ?

I've noticed the project could use some TLC and has not seen a lot of activity over the past few years.
I believe metrics are important to the overall Clojure community and it would be great to have a maintained solution for this.

Thanks,
Eugen

Related:

cc @slipset

Release 2.11

First release as part of clj-commons.
No major changes to code, release as is (if possible) and make process preparations for next release which should contain major changes like dependency upgrades, etc.

All return type hints should be fully-qualified

If return type hints are not fully-qualified, they can require the returned class to be imported in the calling code, which may not even know about the underlying type hint. This is the simplest case where I can cause this to occur with the current code base:

(require 'metrics.timers)
(.stop (metrics.timers/start (metrics.timers/timer "t")))
;; => CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: Timer$Context

I realize this is a nonsensical example, however it can occur in real circumstances where it is impossible for the caller to fix. For example, when using metrics-clojure in tandem with core.async and wishing to wrap a timer around the body of a go block, you could do this:

(require '[clojure.core.async :as async])
(require '[metrics.timers])

(def my-timer (metrics.timers/timer "t"))
(async/go
  (let [c (metrics.timers/start my-timer)]
    (+ 1 1)
    (metrics.timers/stop c)))

;;=> ExceptionInfo Class not found: Timer$Context

The error here is in relation to the non-qualified return type on the metrics.timers/start function. In this case, the place where the class would need to be imported to fix the error is inside a third-party, specifically clojure.tools.analyzer.jvm. So there is no practical way for a user to fix this.

To fix, all return type hints in this library should be fully-qualified.

Here is a comment from Rich Hickey about this behavior: http://dev.clojure.org/jira/browse/CLJ-1232?focusedCommentId=34819&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-34819
Regarding that ticket, I would like to be noisy about this problem when it is created rather than silent as it is now, but this is the current behavior.

Eastwood (https://github.com/jonase/eastwood) has a check for this problem to find it in static analysis under the https://github.com/jonase/eastwood#wrong-tag linter.

Provide a way to start/stop a timer in different parts without wrapping the code that runs

there's an API on metrics to do this:

http://metrics.codahale.com/manual/core/#timers

but the metrics-clojure API only provides (as far as I can see on the docs) time! and time-fn!:

http://metrics-clojure.readthedocs.org/en/latest/metrics/timers.html#time

would it be possible to have an api to do something like:

(def timer (start-timer))

...

; somewhere else

(stop-timer timer)

(the example is just the first idea that came to my mind)

Please release 1.0.1 to clojars

I've just pushed 1.0.1 with fixes to defhistogram and friends that did not compile. The change log is updated.

Also, maybe we should create a branch, like 1.0.x-stable, to cut 1.0.x releases and master can be 1.1.0-SNAPSHOT development.

When is the next release coming out?

I've switched over to using this project and I like it so far. However, I've run into this issue which requires I either add a flag to my JVM startup or upgrade the dropwizard metrics version I'm using. It looks like the current version of master of this project is using a newer version of dropwizard, but the latest release on clojars is quite old. I have a handful of workarounds available to me, but ideally it'd be great to just pull down a new build of this library from clojars. When will the next build be published?

EDIT: Also, the newest version of dropwizard is 4.2.2. So if the new release could point at that version, that'd be great.

Add a way to uninstrument JVM metrics

If I call metrics.jvm.core/instrument-jvm during startup, there is no corresponding metrics.jvm.core/uninstrument-jvm to call during shutdown. This causes problems for me during tests that check startup and shutdown behavior; if I call instrument-jvm twice I get an error "A metric named jvm.attribute.vendor already exists".

I suppose a less desirable alternative that would still address my use-case would be to make instrumentation idempotent. A clean shutdown would be my preference.

Support ring metrics for asynchronous requests

The Aleph web server, built on top of Netty, gives the option of returning a manifold deferred object in addition to the standard ring response map. This allows the request to be carried out asynchronously.

The current instrument middleware assumes a synchronous implementation. It would be great if async was supported as well.

It wouldn't be much work to get this working. Something along the lines of:

(defn wrap-metrics
  [handler]
  (fn [req]
    (start-metrics)
    (let [resp (handler req)]
      (if (instance? manifold.deferred.Deferred resp)
        (on-realized resp stop-metrics)
        (stop-metrics))
      resp)))

Of course, it means introducing manifold as a dependency. It's a small library though, and only introduces a couple of transitive dependencies.

Happy to submit a PR for this.

Per-endpoint ring metrics

Seems like it would be useful to be able to record metrics for each endpoint in an app. In theory since it just wraps a handler, you could wrap each endpoint individually, but then you'd register the same metric twice. Would be nice if the "instrument-ring" function accepted a prefix that could be used to ensure each metric is uniquely named when wrapping multiple endpoints.

Does that make sense? I can come up with a PR if this sounds ok.

StackOverflowError in ganglia reporter

at line 11 of metrics.reporters.ganglia there is a infinite recursion which ends into a StackOverflowError

(defn ^com.codahale.metrics.ganglia.GangliaReporter reporter
  ([ganglia opts]
     (reporter default-registry opts))  ;; ERROR HERE infinite recursion
  ([^MetricRegistry reg ganglia opts]
     (let [b (GangliaReporter/forRegistry reg)]
       (when-let [^TimeUnit ru (:rate-unit opts)]
         (.convertRatesTo b ru))
       (when-let [^TimeUnit du (:duration-unit opts)]
         (.convertDurationsTo b du))
       (when-let [^MetricFilter f (:filter opts)]
         (.filter b f))
       (.build b ganglia))))

Some way to get, stop, and remove all the reporters.

I'm trying to run some integration tests, and want metrics to be cleanly stopped and then later restarted. I've not found any way to stop the various reporters other than by keeping track of them when I add them. Do you have any ideas?

Ability to retrieve a gauge by name

Hi!

For all other types, it's possible to retrieve the metric by its name. For example (meter reg ["alpha" "beta" "gamma"]) will retrieve the meter if it already exists. There is no such possibility for a gauge. Maybe adding a gauge method for that (which won't allow creation)?

def<metric> macros prevent uberjar creation

One or more of the def<metric> macros prevent lein uberjar from compiling successfully.

I've created a gist with a minimal project that exhibits the behavior. You can see it at: https://gist.github.com/ewollesen/33d6b6585bb8a7267be4

My setup:

$ uname -a
Darwin quill 14.1.0 Darwin Kernel Version 14.1.0: Mon Dec 22 23:10:38 PST 2014; root:xnu-2782.10.72~2/RELEASE_X86_64 x86_64 i386 MacBookPro10,1 Darwin
$ lein version
Leiningen 2.5.1 on Java 1.8.0_31 Java HotSpot(TM) 64-Bit Server VM

My clojure version is 1.6

As a workaround, I was able to use the non-macro functions to create the metrics I needed with no problems.

I debugged the issue with a few of my more knowledgeable co-workers, and one of them suggested that in the macro definitions, the default-registry object is being escaped, and this escaping is what is causing the problems with uberjar creation.

Riemann reporter doesn't appear to work

I use 2.7.0 version, the lein install doesn't appear to do anything or takes ages when I cloned this repository.

Mainly I see this in the logs:

2016-06-21 12:06:58,449 DEBUG (metrics-riemann-reporter-thread-1) [com.codahale.metrics.riemann.RiemannReporter] - Reporting metrics: for 1466503618 at 1466503618449

only once, and I can't see the data in Riemann.

Riemann appear to works as I tried to add metrics manually. I don't have any hint on how to make it works.

I use call this function at start time:

(defn init! []
 (let [host "127.0.0.1"
          port 5555
          riemann-client (riemann/make-riemann host port)
          riemann-reporter (riemann/reporter riemann-client
                                             {:rate-unit TimeUnit/SECONDS
                                              :duration-unit TimeUnit/MILLISECONDS
                                              :filter MetricFilter/ALL})]
      (log/debug (str "connecting to Riemann: " host ":" port))
      (riemann/start riemann-reporter 1)))

Add an (update! [timer time unit]) function

In some cases you have no way to wrap the execution of a task, but you do get reported how long it took. An (update! timer time unit) will help in these cases.

The original codahle Timer has a corresponding update() method which can be used to achieve this.

Example implementation:

(defn update! [^Timer t ^long duration, ^TimeUnit unit]
  (.update t duration unit))

Filtering metrics with Clojure functions

We're using Hosted Graphite (great service btw), and we are charged by our metric count. We have ring metrics, JVM metrics, and custom metrics and are going over our cap. I'd like to filter some of the ring metrics as we only need a few from here, but it's not clear if/how to do that? I read the docs on removing metrics, but it seemed like they would just be recreated later.

What's the recommended way of filtering the metrics that get sent to a (graphite) reporter?

3-arity version of `metrics.timers/timer` is not implemented

The arity-3 version of metrics.timers/deftimer tries to call timer with 3 arguments, which is not implemented. I guess it should either be dropped or call timer-with-reservoir. On a related note, is there a reason why timer passes the title through metrics.core/metric-name while timer-with-reservoir doesn't?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.