This library sends application metrics collected with the standard Dropwizard Metrics into Anodot, which will detect anomalies in your application automatically. Your existing MetricRegistry
(or MetricsRegistry
in versions <= 2.x) will be mirrored by an Anodot registry, which will be dumped periodically to Anodot.
This library relies heavily on Anodot's own anodot-metrics library, which introduces an AnodotRegistry
that mimics the original MetricRegistry
; However, on its own, anodot-metrics
does not easily lend itself for reporting metrics from existing MetricRegistries - which becomes extremely easy with anodot-metrics-bridge
: your entire application can keep using metrics
while completely agnostic as to whether it also reports into Anodot or not.
For a simple usage example, see AnodotReporterFactoryExample.java
Artifacts currently hosted on jitpack.io - follow these steps to include in your Gradle build:
- Add Jitpack repository:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
- Find out what the latest release is, let's assume it's
v0.1.14
- Add the relevant dependency to your project -
anodot-reporter2
,anodot-reporter3
, or both:
dependencies {
// to use with com.yammer.metrics:metrics-core:2.2.0
compile 'com.github.kenshoo.anodot-metrics-bridge:anodot-reporter2:v0.1.14'
// to use with com.codahale.metrics:metrics-core:3.0.2
compile 'com.github.kenshoo.anodot-metrics-bridge:anodot-reporter3:v0.1.14'
}
- Supports both major Metrics versions: 2.x (
com.codahale.metrics
) and 3.x (com.yammer.metrics.core
); These two versions can even be supported side-by-side in same application - Conversion of Metric names into Anodot properties such as
package
andclass
- Supports custom metric filters
- Supports global properties added to all reported metrics (e.g.
server
,version
,app
etc.) - Reporters are stoppable and restartable
Metrics and Anodot differ greatly in their modeling of metrics
- Metrics uses a hierarchial structure, represented by a dot-separated String, e.g.
path.to.metric
. By convention, the hierarchy will start with the reporting class's package name (which is usually a lowercase, dot-separated String by itself), continue with the class name (usually an alphanumeric, PascalCase String), and end with an N-deep hierarchy or camelCase strings describing the actual metric being measured (e.g.processedFiles.number.value
,processedFiles.rate.max
) - Anodot uses a key-value map of properties, where each property can later be grouped-by or filtered-by when defining graphs and anomalies in Anodot. One property is mandatory, and that's the
what
propery - which should represent the actual measurement. Additionally, dots are used as a special character separating key-value pairs, so property names and property values must not contain dots
Metric names are therefore parsed into Anodot metrics assuming these conventions are kept. Some examples:
-
Common case:
com.kenshoo.metrics.MetricService.processedMetrics.max
will be converted into:package
=>com_kenshoo_metrics
class
=>MetricService
what
=>processedMetrics_max
-
No identifyable class name:
com.kenshoo.metrics.metricservice.max
will be converted into:what
=>com_kenshoo_metrics_metricservice_max
-
Poorly Identified case: if your naming does not follow convensions, e.g. if you have capital letters in a package name, conversion might end up confused, e.g.
com.kenshoo.MyPackage.MyClass.myMetric
will be converted into:package
=>com_kenshoo
class
=>MyPackege
what
=>MyClass_myMetric
By default, all metrics are filtered out (i.e. not sent) until they contain at least one non-zero value. You can disable this filtering (thus forcing all metrics to be reported immediately, even before they contain any actual information) by calling turnZeroFilterOff()
on the Anodot2ReporterBuilder
instance while building a reporter:
final AnodotReporterWrapper reporter = Anodot3ReporterBuilder.builderFor(anodotConf)
.turnZeroFilterOff()
.build(metricRegistry);
You can extend com.anodot.metrics.AnodotMetricFilter
(or com.yammer.metrics.core.AnodotMetricFilter
for V2) with your own filtering logic, and register that filter by calling addFilter(AnodotMetricFilter filter)
on the Anodot2ReporterBuilder
instance; You can add as many filters as you like - a metric will be reported if and only if it passed all filters
For example, to build a reporter with a custom filter that would only report metrics from a certain package:
final AnodotReporterWrapper reporter = Anodot3ReporterBuilder.builderFor(anodotConf)
.addFilter(new AnodotMetricFilter() {
// include only metrics from from package "com.kenshoo.*"
@Override
public boolean matches(MetricName metricName, Metric metric) {
return metricName.getProperty("package").getValue().startsWith("com_kenshoo");
}
})
.build(metricRegistry);
You can define a set of global peroperties - constants which will be added to the key-value set of properties for all metrics reported for a specific registry. This is useful for properties that are "static" per JVM, e.g. server
, version
, build
, app-id
etc.
To add a custom set of properties, implement and instantiate a AnodotGlobalProperties
and pass it to Anodot3ReporterBuilder
's withGlobalProperties
. For example, here's a AnodotGlobalProperties
with a version
and app-id
:
final AnodotReporterWrapper reporter = Anodot3ReporterBuilder.builderFor(anodotConf)
.withGlobalProperties(new AnodotGlobalProperties() {
@Override
public Map<String, String> propertyMap() {
return ImmutableMap.of(
"app-id", "frontEnd.requestHandler",
"version", "v1.0.12");
}
})
.build(metricRegistry);
You can also use the existing DefaultAnodotGlobalProperties
which reports server
, version
and build
properties - just instantiate it with the relevant values:
final AnodotReporterWrapper reporter = Anodot3ReporterBuilder.builderFor(anodotConf)
.withGlobalProperties(new DefaultAnodotGlobalProperties("v1.0.12", "233", "frontHost-1"))
.build(metricRegistry);
DefaultAnodotGlobalProperties
can also infer the server name automatically (using InetAddress.getLocalHost().getHostName()
) - just call the constructor overload that expects version and build only:
final AnodotReporterWrapper reporter = Anodot3ReporterBuilder.builderFor(anodotConf)
.withGlobalProperties(new DefaultAnodotGlobalProperties("v1.0.12", "233"))
.build(metricRegistry);
Issues / PRs are welcome! While maintainer responses might sometimes be delayed, your issues will not be dismissed :)