Skip to content

Commit

Permalink
AvastJmxMetricsMonitor (#27)
Browse files Browse the repository at this point in the history
AvastJmxMetricsMonitor
  • Loading branch information
jendakol authored Oct 12, 2017
1 parent 0c3e6e2 commit e10c65b
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 5 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ The entry-point into the library is the interface `Monitor`. Your classes need t
Instances of the individuals metrics can be used to monitor your application.

Currently there are multiple implementations/exports:
* [JMX](jmx)
* [JMX](jmx) (+ Avast specific format of export [jmx-avast](jmx-avast))
* [Graphite](graphite)
* [StatsD](statsd)
* [Formatting](formatting) to string in configurable formats, e.g. for serving via HTTP server

There is Scala API available in `metrics-scala`. See the example below.

## Adding to project
The library is published to [Bintray](https://bintray.com/avast/maven/metrics/) E.g. usage of the [StatsD](statsd) in Gradle project:
The library is published to [Bintray](https://bintray.com/avast/maven/metrics/). Example usage of the [StatsD](statsd) in Gradle project:
```gradle
repositories {
jcenter()
Expand Down
9 changes: 8 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ lazy val root = (project in file("."))
name := "metrics",
publish := {},
publishLocal := {}
).aggregate(api, scalaApi, core, dropwizardCommon, jmx, graphite, filter, formatting, statsd)
).aggregate(api, scalaApi, core, dropwizardCommon, jmx, jmxAvast, graphite, filter, formatting, statsd)

lazy val api = (project in file("api")).
settings(
Expand Down Expand Up @@ -107,6 +107,13 @@ lazy val jmx = (project in file("jmx")).
name := "metrics-jmx"
).dependsOn(dropwizardCommon)

lazy val jmxAvast = (project in file("jmx-avast")).
settings(
commonSettings,
javaSettings,
name := "metrics-jmx-avast"
).dependsOn(jmx)

lazy val graphite = (project in file("graphite")).
settings(
commonSettings,
Expand Down
20 changes: 20 additions & 0 deletions jmx-avast/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Dropwizard JMX export - Avast custom

See [AvastJmxMetricsMonitor](src/main/java/com/avast/metrics/dropwizard/AvastJmxMetricsMonitor.java) and
[AvastTreeObjectNameFactoryTest](src/test/java/com/avast/metrics/dropwizard/AvastTreeObjectNameFactoryTest.java).

```java
import com.avast.metrics.api.*;
import com.avast.metrics.dropwizard.*;

AvastJmxMetricsMonitor monitor = new AvastJmxMetricsMonitor("com.avast.myapp");
Handler handler = new Handler(monitor.named("Handler1"));
```

```scala
import com.avast.metrics.scalaapi.Monitor
import com.avast.metrics.dropwizard.AvastJmxMetricsMonitor

val javaMonitor = new AvastJmxMetricsMonitor("com.avast.myapp")
val scalaMonitor = Monitor(javaMonitor)
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.avast.metrics.dropwizard;

import com.avast.metrics.api.Naming;
import com.codahale.metrics.MetricRegistry;

@SuppressWarnings("WeakerAccess")
public class AvastJmxMetricsMonitor extends JmxMetricsMonitor {

public AvastJmxMetricsMonitor(String domain) {
this(domain, new MetricRegistry(), Naming.defaultNaming());
}

public AvastJmxMetricsMonitor(String domain, MetricRegistry metricRegistry, Naming naming) {
super(AvastTreeObjectNameFactory.getInstance(), domain, metricRegistry, naming);
}

private AvastJmxMetricsMonitor(AvastJmxMetricsMonitor original, String... names) {
super(original, names);
}


@Override
public AvastJmxMetricsMonitor named(String name) {
return new AvastJmxMetricsMonitor(this, name);
}

@Override
public AvastJmxMetricsMonitor named(String name1, String name2, String... restOfNames) {
return new AvastJmxMetricsMonitor(named(name1).named(name2), restOfNames);
}

@Override
protected String separator() {
return AvastTreeObjectNameFactory.SEPARATOR;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.avast.metrics.dropwizard;

import com.codahale.metrics.DefaultObjectNameFactory;
import com.codahale.metrics.ObjectNameFactory;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import java.util.*;
import java.util.regex.Pattern;

/**
* This is the Avast alternative for {@link TreeObjectNameFactory}. It uses "type-scope-name" format of resulting {@link ObjectName} (levels
* 3-N are glued together).
* See unit tests.
*/
public class AvastTreeObjectNameFactory implements ObjectNameFactory {

public static final String SEPARATOR = "@#*";

private static final ObjectNameFactory defaultFactory = new DefaultObjectNameFactory();

private static final String[] partNames = {"type", "scope", "name"};

private AvastTreeObjectNameFactory() {
}

public static AvastTreeObjectNameFactory getInstance() {
return Holder.INSTANCE;
}

@Override
public ObjectName createName(String type, String domain, String name) {
Optional<ObjectName> parsedName = parseName(domain, name);
return parsedName.orElse(defaultFactory.createName(type, domain, name));
}

private Optional<ObjectName> parseName(String domain, String name) {
try {
final String[] parts = name.split(Pattern.quote(SEPARATOR), partNames.length);

/*
Following block of code is a little hack.
The problem is the `ObjectName` requires `HashTable` as parameter but the `HashTable` is unsorted and
thus unusable for us. We hack it by raping the `HashTable` and in-fact using `LinkedHashMap` which is
much more suitable for our needs.
*/

final LinkedHashMap<String, String> map = new LinkedHashMap<>();
final Hashtable<String, String> properties = new Hashtable<String, String>() {
@Override
public Set<Map.Entry<String, String>> entrySet() {
return map.entrySet();
}
};

for (int i = 0; i < parts.length; i++) {
properties.put(partNames[i], quote(parts[i]));
map.put(partNames[i], quote(parts[i]));
}

return Optional.of(new ObjectName(domain, properties));
} catch (MalformedObjectNameException ex) {
return Optional.empty();
}
}


private String quote(String objectName) {
return objectName
.replaceAll(Pattern.quote(SEPARATOR), "/")
.replaceAll("[\\Q?*\"\\E]", "_");
}

private static class Holder {
static final AvastTreeObjectNameFactory INSTANCE = new AvastTreeObjectNameFactory();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.avast.metrics.dropwizard;

import com.avast.metrics.api.Gauge;
import com.avast.metrics.api.Monitor;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.junit.Assert.assertEquals;

public class AvastMetricsMonitorTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void jmxClose() {
try (Monitor m1 = new AvastJmxMetricsMonitor("com.avast.metrics.test").named("test-jmx-close")) {
int value1 = 1;
Gauge<Integer> gauge1 = m1.newGauge("gauge", () -> value1);
assertEquals(value1, (int) gauge1.getValue());
}

try (Monitor m2 = new AvastJmxMetricsMonitor("com.avast.metrics.test").named("test-jmx-close")) {
int value2 = 2;
Gauge<Integer> gauge2 = m2.newGauge("gauge", () -> value2);
assertEquals(value2, (int) gauge2.getValue());
}

// watch log output for javax.management.InstanceAlreadyExistsException
}

@Test
public void getName() {
try (AvastJmxMetricsMonitor m1 = new AvastJmxMetricsMonitor("com.avast.metrics.test").named("first", "second", "third", "fourth")) {
final String name = m1.getName();

assertEquals("first/second/third/fourth", name);
}

try (Monitor m1 = new AvastJmxMetricsMonitor("com.avast.metrics.test").named("first/sub").named("second").named("third").named("fourth/fifth")) {
try (Monitor m2 = new JmxMetricsMonitor("com.avast.metrics.test").named("first/sub", "second", "third").named("fourth/fifth")) {
final String name1 = m1.getName();
final String name2 = m2.getName();

assertEquals(name1, name2);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.avast.metrics.dropwizard;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.junit.Assert.assertEquals;

public class AvastTreeObjectNameFactoryTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void createName() {
final AvastTreeObjectNameFactory nameFactory = AvastTreeObjectNameFactory.getInstance();

final String name = nameFactory.createName("theType", "theDomain", String.join(AvastTreeObjectNameFactory.SEPARATOR, "l1", "l2", "l3", "l4", "l5")).toString();

assertEquals("theDomain:type=l1,scope=l2,name=l3/l4/l5", name);
}
}
2 changes: 1 addition & 1 deletion jmx/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Dropwizard JMX export

See [JmxMetricsMonitor](jmx/src/main/java/com/avast/metrics/dropwizard/JmxMetricsMonitor.java).
See [JmxMetricsMonitor](src/main/java/com/avast/metrics/dropwizard/JmxMetricsMonitor.java).

```java
import com.avast.metrics.api.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public JmxMetricsMonitor(ObjectNameFactory objectNameFactory, String domain, Met
}
}

private JmxMetricsMonitor(JmxMetricsMonitor original, String... names) {
protected JmxMetricsMonitor(JmxMetricsMonitor original, String... names) {
super(original, names);
this.reporter = original.reporter;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.avast.metrics.dropwizard;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.junit.Assert.assertEquals;

public class TreeObjectNameFactoryTest {


@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void createName() {
final TreeObjectNameFactory nameFactory = TreeObjectNameFactory.getInstance();

final String name = nameFactory.createName("theType", "theDomain", String.join(TreeObjectNameFactory.SEPARATOR, "l1", "l2", "l3", "l4", "l5")).toString();

assertEquals("theDomain:level0=l1,level1=l2,level2=l3,level3=l4,level4=l5",name);
}
}

0 comments on commit e10c65b

Please sign in to comment.