diff --git a/metrics-core/pom.xml b/metrics-core/pom.xml index 5cf45c4a45..09cd53374f 100644 --- a/metrics-core/pom.xml +++ b/metrics-core/pom.xml @@ -13,6 +13,11 @@ bundle + + com.yammer.metrics + metrics-annotation + ${project.version} + org.slf4j slf4j-api diff --git a/metrics-core/src/main/java/com/yammer/metrics/core/MetricName.java b/metrics-core/src/main/java/com/yammer/metrics/core/MetricName.java index 117427e3ea..76826efdd2 100644 --- a/metrics-core/src/main/java/com/yammer/metrics/core/MetricName.java +++ b/metrics-core/src/main/java/com/yammer/metrics/core/MetricName.java @@ -1,16 +1,17 @@ package com.yammer.metrics.core; +import com.yammer.metrics.annotation.ExceptionMetered; + import java.lang.reflect.Method; /** * A value class encapsulating a metric's owning class and name. */ public class MetricName implements Comparable { - private final String group; + private final String domain; private final String type; private final String name; private final String scope; - private final String mBeanName; /** * Creates a new {@link MetricName} without a scope. @@ -25,12 +26,12 @@ public MetricName(Class klass, String name) { /** * Creates a new {@link MetricName} without a scope. * - * @param group the group to which the {@link Metric} belongs + * @param domain the domain to which the {@link Metric} belongs * @param type the type to which the {@link Metric} belongs * @param name the name of the {@link Metric} */ - public MetricName(String group, String type, String name) { - this(group, type, name, null); + public MetricName(String domain, String type, String name) { + this(domain, type, name, null); } /** @@ -41,8 +42,8 @@ public MetricName(String group, String type, String name) { * @param scope the scope of the {@link Metric} */ public MetricName(Class klass, String name, String scope) { - this(klass.getPackage() == null ? "" : klass.getPackage().getName(), - klass.getSimpleName().replaceAll("\\$$", ""), + this(getPackageName(klass), + getClassName(klass), name, scope); } @@ -50,47 +51,32 @@ public MetricName(Class klass, String name, String scope) { /** * Creates a new {@link MetricName} without a scope. * - * @param group the group to which the {@link Metric} belongs + * @param domain the domain to which the {@link Metric} belongs * @param type the type to which the {@link Metric} belongs * @param name the name of the {@link Metric} * @param scope the scope of the {@link Metric} */ - public MetricName(String group, String type, String name, String scope) { - this(group, type, name, scope, createMBeanName(group, type, name, scope)); - } - - /** - * Creates a new {@link MetricName} without a scope. - * - * @param group the group to which the {@link Metric} belongs - * @param type the type to which the {@link Metric} belongs - * @param name the name of the {@link Metric} - * @param scope the scope of the {@link Metric} - * @param mBeanName the 'ObjectName', represented as a string, to use when registering the - * MBean. - */ - public MetricName(String group, String type, String name, String scope, String mBeanName) { - if (group == null || type == null) { - throw new IllegalArgumentException("Both group and type need to be specified"); + public MetricName(String domain, String type, String name, String scope) { + if (domain == null || type == null) { + throw new IllegalArgumentException("Both domain and type need to be specified"); } if (name == null) { throw new IllegalArgumentException("Name needs to be specified"); } - this.group = group; + this.domain = domain; this.type = type; this.name = name; this.scope = scope; - this.mBeanName = mBeanName; } /** - * Returns the group to which the {@link Metric} belongs. For class-based metrics, this will be + * Returns the domain to which the {@link Metric} belongs. For class-based metrics, this will be * the package name of the {@link Class} to which the {@link Metric} belongs. * - * @return the group to which the {@link Metric} belongs + * @return the domain to which the {@link Metric} belongs */ - public String getGroup() { - return group; + public String getDomain() { + return domain; } /** @@ -130,90 +116,113 @@ public boolean hasScope() { return scope != null; } - /** - * Returns the MBean name for the {@link Metric} identified by this metric name. - * - * @return the MBean name - */ - public String getMBeanName() { - return mBeanName; - } - @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } final MetricName that = (MetricName) o; - return mBeanName.equals(that.mBeanName); + return domain.equals(that.domain) && + name.equals(that.name) && + type.equals(that.type) && + (scope == null ? that.scope == null : scope.equals(that.scope)); } @Override public int hashCode() { - return mBeanName.hashCode(); + int result = domain.hashCode(); + result = 31 * result + type.hashCode(); + result = 31 * result + name.hashCode(); + result = 31 * result + (scope != null ? scope.hashCode() : 0); + return result; } @Override public String toString() { - return mBeanName; + return domain + '.' + type + '.' + name + (scope == null ? "" : '.' + scope); } @Override public int compareTo(MetricName o) { - return mBeanName.compareTo(o.mBeanName); - } + int result = domain.compareTo(o.domain); + if (result != 0) { + return result; + } - private static String createMBeanName(String group, String type, String name, String scope) { - final StringBuilder nameBuilder = new StringBuilder(); - nameBuilder.append(group); - nameBuilder.append(":type="); - nameBuilder.append(type); - if (scope != null) { - nameBuilder.append(",scope="); - nameBuilder.append(scope); + result = type.compareTo(o.type); + if (result != 0) { + return result; } - if (name.length() > 0) { - nameBuilder.append(",name="); - nameBuilder.append(name); + + result = name.compareTo(o.name); + if (result != 0) { + return result; + } + + if (scope == null) { + if (o.scope != null) { + return -1; + } + return 0; + } + + if (o.scope != null) { + return scope.compareTo(o.scope); } - return nameBuilder.toString(); + return 1; } - /** - * If the group is empty, use the package name of the given class. Otherwise use group - * @param group The group to use by default - * @param klass The class being tracked - * @return a group for the metric - */ - public static String chooseGroup(String group, Class klass) { - if(group == null || group.isEmpty()) { - group = klass.getPackage() == null ? "" : klass.getPackage().getName(); + private static String getPackageName(Class klass) { + return klass.getPackage() == null ? "" : klass.getPackage().getName(); + } + + private static String getClassName(Class klass) { + return klass.getSimpleName().replaceAll("\\$$", ""); + } + + private static String chooseDomain(String domain, Class klass) { + if(domain == null || domain.isEmpty()) { + domain = getPackageName(klass); } - return group; + return domain; } - /** - * If the type is empty, use the simple name of the given class. Otherwise use type - * @param type The type to use by default - * @param klass The class being tracked - * @return a type for the metric - */ - public static String chooseType(String type, Class klass) { + private static String chooseType(String type, Class klass) { if(type == null || type.isEmpty()) { - type = klass.getSimpleName().replaceAll("\\$$", ""); + type = getClassName(klass); } return type; } - /** - * If name is empty, use the name of the given method. Otherwise use name - * @param name The name to use by default - * @param method The method being tracked - * @return a name for the metric - */ - public static String chooseName(String name, Method method) { + private static String chooseName(String name, Method method) { if(name == null || name.isEmpty()) { name = method.getName(); } return name; } + + public static MetricName forTimedMethod(Class klass, Method method, com.yammer.metrics.annotation.Timed annotation) { + return new MetricName(chooseDomain(annotation.group(), klass), + chooseType(annotation.type(), klass), + chooseName(annotation.name(), method)); + } + + public static MetricName forMeteredMethod(Class klass, Method method, com.yammer.metrics.annotation.Metered annotation) { + return new MetricName(chooseDomain(annotation.group(), klass), + chooseType(annotation.type(), klass), + chooseName(annotation.name(), method)); + } + + public static MetricName forGaugeMethod(Class klass, Method method, com.yammer.metrics.annotation.Gauge annotation) { + return new MetricName(chooseDomain(annotation.group(), klass), + chooseType(annotation.type(), klass), + chooseName(annotation.name(), method)); + } + + public static MetricName forExceptionMeteredMethod(Class klass, Method method, com.yammer.metrics.annotation.ExceptionMetered annotation) { + return new MetricName(chooseDomain(annotation.group(), klass), + chooseType(annotation.type(), klass), + annotation.name() == null || annotation.name().isEmpty() ? + method.getName() + ExceptionMetered.DEFAULT_NAME_SUFFIX : + annotation.name()); + } } diff --git a/metrics-core/src/main/java/com/yammer/metrics/core/MetricsRegistry.java b/metrics-core/src/main/java/com/yammer/metrics/core/MetricsRegistry.java index 60b7ba962c..e0220bf31f 100644 --- a/metrics-core/src/main/java/com/yammer/metrics/core/MetricsRegistry.java +++ b/metrics-core/src/main/java/com/yammer/metrics/core/MetricsRegistry.java @@ -348,7 +348,7 @@ public SortedMap> getGroupedMetrics(Metric final SortedMap> groups = new TreeMap>(); for (Map.Entry entry : metrics.entrySet()) { - final String qualifiedTypeName = entry.getKey().getGroup() + "." + entry.getKey() + final String qualifiedTypeName = entry.getKey().getDomain() + "." + entry.getKey() .getType(); if (predicate.matches(entry.getKey(), entry.getValue())) { final String scopedName; diff --git a/metrics-core/src/main/java/com/yammer/metrics/reporting/JmxReporter.java b/metrics-core/src/main/java/com/yammer/metrics/reporting/JmxReporter.java index 3a6957a662..2cbdbfa80f 100644 --- a/metrics-core/src/main/java/com/yammer/metrics/reporting/JmxReporter.java +++ b/metrics-core/src/main/java/com/yammer/metrics/reporting/JmxReporter.java @@ -394,13 +394,29 @@ public JmxReporter(MetricsRegistry registry) { public void onMetricAdded(MetricName name, Metric metric) { if (metric != null) { try { - dispatcher.dispatch(metric, name, this, new Context(name, new ObjectName(name.getMBeanName()))); + dispatcher.dispatch(metric, name, this, new Context(name, createObjectName(name))); } catch (Exception e) { LOGGER.warn("Error processing {}", name, e); } } } + private ObjectName createObjectName(MetricName name) throws MalformedObjectNameException { + final StringBuilder nameBuilder = new StringBuilder(); + nameBuilder.append(name.getDomain()); + nameBuilder.append(":type="); + nameBuilder.append(name.getType()); + if (name.hasScope()) { + nameBuilder.append(",scope="); + nameBuilder.append(name.getScope()); + } + if (!name.getName().isEmpty()) { + nameBuilder.append(",name="); + nameBuilder.append(name); + } + return new ObjectName(nameBuilder.toString()); + } + @Override public void onMetricRemoved(MetricName name) { final ObjectName objectName = registeredBeans.remove(name); diff --git a/metrics-core/src/test/java/com/yammer/metrics/core/tests/MetricNameTest.java b/metrics-core/src/test/java/com/yammer/metrics/core/tests/MetricNameTest.java index e61a4e1675..ff9e52f34f 100644 --- a/metrics-core/src/test/java/com/yammer/metrics/core/tests/MetricNameTest.java +++ b/metrics-core/src/test/java/com/yammer/metrics/core/tests/MetricNameTest.java @@ -7,11 +7,11 @@ import static org.junit.Assert.*; public class MetricNameTest { - private final MetricName name = new MetricName("group", "type", "name", "scope", "bean"); + private final MetricName name = new MetricName("group", "type", "name", "scope"); @Test public void hasAGroup() throws Exception { - assertThat(name.getGroup(), + assertThat(name.getDomain(), is("group")); } @@ -36,16 +36,10 @@ public void hasAScope() throws Exception { is(true)); } - @Test - public void hasAnMBeanName() throws Exception { - assertThat(name.getMBeanName(), - is("bean")); - } - @Test public void isHumanReadable() throws Exception { assertThat(name.toString(), - is("bean")); + is("group.type.name.scope")); } @Test @@ -53,7 +47,7 @@ public void createsNamesForSimpleMetrics() throws Exception { final MetricName simple = new MetricName(MetricNameTest.class, "name"); assertThat("it uses the package name as the group", - simple.getGroup(), + simple.getDomain(), is("com.yammer.metrics.core.tests")); assertThat("it uses the class name as the type", @@ -67,10 +61,6 @@ public void createsNamesForSimpleMetrics() throws Exception { assertThat("it has a name", simple.getName(), is("name")); - - assertThat("it has an MBean name", - simple.getMBeanName(), - is("com.yammer.metrics.core.tests:type=MetricNameTest,name=name")); } @Test @@ -78,7 +68,7 @@ public void createsNamesForScopedMetrics() throws Exception { final MetricName scoped = new MetricName(MetricNameTest.class, "name", "scope"); assertThat("it uses the package name as the group", - scoped.getGroup(), + scoped.getDomain(), is("com.yammer.metrics.core.tests")); assertThat("it uses the class name as the type", @@ -92,10 +82,6 @@ public void createsNamesForScopedMetrics() throws Exception { assertThat("it has a name", scoped.getName(), is("name")); - - assertThat("it has an MBean name", - scoped.getMBeanName(), - is("com.yammer.metrics.core.tests:type=MetricNameTest,scope=scope,name=name")); } @Test @@ -110,15 +96,15 @@ public void hasAWorkingEqualsImplementation() throws Exception { is(not(equalTo((Object) "")))); assertThat(name, - is(equalTo(new MetricName("group", "type", "name", "scope", "bean")))); + is(equalTo(new MetricName("group", "type", "name", "scope")))); } @Test public void hasAWorkingHashCodeImplementation() throws Exception { - assertThat(new MetricName("group", "type", "name", "scope", "bean").hashCode(), - is(equalTo(new MetricName("group", "type", "name", "scope", "bean").hashCode()))); + assertThat(new MetricName("group", "type", "name", "scope").hashCode(), + is(equalTo(new MetricName("group", "type", "name", "scope").hashCode()))); - assertThat(new MetricName("group", "type", "name", "scope", "bean").hashCode(), - is(not(equalTo(new MetricName("group", "type", "name", "scope", "bean2").hashCode())))); + assertThat(new MetricName("group", "type", "name", "scope").hashCode(), + is(not(equalTo(new MetricName("group", "type", "name", "scope2").hashCode())))); } } diff --git a/metrics-ganglia/src/main/java/com/yammer/metrics/ganglia/GangliaReporter.java b/metrics-ganglia/src/main/java/com/yammer/metrics/ganglia/GangliaReporter.java index fc1891f9a9..5d90053008 100644 --- a/metrics-ganglia/src/main/java/com/yammer/metrics/ganglia/GangliaReporter.java +++ b/metrics-ganglia/src/main/java/com/yammer/metrics/ganglia/GangliaReporter.java @@ -461,7 +461,7 @@ protected String sanitizeName(MetricName name) { if (name == null) { return ""; } - final String qualifiedTypeName = name.getGroup() + "." + name.getType() + "." + name.getName(); + final String qualifiedTypeName = name.getDomain() + "." + name.getType() + "." + name.getName(); final String metricName = name.hasScope() ? qualifiedTypeName + '.' + name.getScope() : qualifiedTypeName; final StringBuilder sb = new StringBuilder(); for (int i = 0; i < metricName.length(); i++) { diff --git a/metrics-graphite/src/main/java/com/yammer/metrics/graphite/GraphiteReporter.java b/metrics-graphite/src/main/java/com/yammer/metrics/graphite/GraphiteReporter.java index 1186e5d5f3..502268b3a3 100644 --- a/metrics-graphite/src/main/java/com/yammer/metrics/graphite/GraphiteReporter.java +++ b/metrics-graphite/src/main/java/com/yammer/metrics/graphite/GraphiteReporter.java @@ -287,7 +287,7 @@ protected void sendToGraphite(long timestamp, String name, String value) { protected String sanitizeName(MetricName name) { final StringBuilder sb = new StringBuilder() - .append(name.getGroup()) + .append(name.getDomain()) .append('.') .append(name.getType()) .append('.'); diff --git a/metrics-jersey/src/main/java/com/yammer/metrics/jersey/InstrumentedResourceMethodDispatchProvider.java b/metrics-jersey/src/main/java/com/yammer/metrics/jersey/InstrumentedResourceMethodDispatchProvider.java index ad5c2c08d9..c74b1c4410 100644 --- a/metrics-jersey/src/main/java/com/yammer/metrics/jersey/InstrumentedResourceMethodDispatchProvider.java +++ b/metrics-jersey/src/main/java/com/yammer/metrics/jersey/InstrumentedResourceMethodDispatchProvider.java @@ -7,15 +7,10 @@ import com.yammer.metrics.annotation.ExceptionMetered; import com.yammer.metrics.annotation.Metered; import com.yammer.metrics.annotation.Timed; -import com.yammer.metrics.core.Meter; -import com.yammer.metrics.core.MetricName; -import com.yammer.metrics.core.MetricsRegistry; -import com.yammer.metrics.core.Timer; -import com.yammer.metrics.core.TimerContext; +import com.yammer.metrics.core.*; import sun.misc.Unsafe; import java.lang.reflect.Field; -import java.util.concurrent.TimeUnit; class InstrumentedResourceMethodDispatchProvider implements ResourceMethodDispatchProvider { private static class TimedRequestDispatcher implements RequestDispatcher { @@ -92,7 +87,7 @@ private static Unsafe getUnsafe() { } private final ResourceMethodDispatchProvider provider; - private MetricsRegistry registry; + private final MetricsRegistry registry; public InstrumentedResourceMethodDispatchProvider(ResourceMethodDispatchProvider provider, MetricsRegistry registry) { this.provider = provider; @@ -108,57 +103,34 @@ public RequestDispatcher create(AbstractResourceMethod method) { if (method.getMethod().isAnnotationPresent(Timed.class)) { final Timed annotation = method.getMethod().getAnnotation(Timed.class); - - Class klass = method.getDeclaringResource().getResourceClass(); - String group = MetricName.chooseGroup(annotation.group(), klass); - String type = MetricName.chooseType(annotation.type(), klass); - String name = MetricName.chooseName(annotation.name(), method.getMethod()); - MetricName metricName = new MetricName(group, type, name); - - final Timer timer = registry.newTimer(metricName, - annotation.durationUnit() == null ? - TimeUnit.MILLISECONDS : annotation.durationUnit(), - annotation.rateUnit() == null ? - TimeUnit.SECONDS : annotation.rateUnit()); + final MetricName name = MetricName.forTimedMethod(method.getDeclaringResource() + .getResourceClass(), + method.getMethod(), + annotation); + final Timer timer = registry.newTimer(name, annotation.durationUnit(), annotation.rateUnit()); dispatcher = new TimedRequestDispatcher(dispatcher, timer); } if (method.getMethod().isAnnotationPresent(Metered.class)) { final Metered annotation = method.getMethod().getAnnotation(Metered.class); - - Class klass = method.getDeclaringResource().getResourceClass(); - String group = MetricName.chooseGroup(annotation.group(), klass); - String type = MetricName.chooseType(annotation.type(), klass); - String name = MetricName.chooseName(annotation.name(), method.getMethod()); - MetricName metricName = new MetricName(group, type, name); - - final Meter meter = registry.newMeter(metricName, - annotation.eventType() == null ? - "requests" : annotation.eventType(), - annotation.rateUnit() == null ? - TimeUnit.SECONDS : annotation.rateUnit()); + final MetricName name = MetricName.forMeteredMethod(method.getDeclaringResource() + .getResourceClass(), + method.getMethod(), + annotation); + final Meter meter = registry.newMeter(name, annotation.eventType(), annotation.rateUnit()); dispatcher = new MeteredRequestDispatcher(dispatcher, meter); } if (method.getMethod().isAnnotationPresent(ExceptionMetered.class)) { final ExceptionMetered annotation = method.getMethod().getAnnotation(ExceptionMetered.class); - - Class klass = method.getDeclaringResource().getResourceClass(); - String group = MetricName.chooseGroup(annotation.group(), klass); - String type = MetricName.chooseType(annotation.type(), klass); - String name = annotation.name() == null || annotation.name().equals("") ? - method.getMethod().getName() + ExceptionMetered.DEFAULT_NAME_SUFFIX : annotation.name(); - MetricName metricName = new MetricName(group, type, name); - - final Meter meter = registry.newMeter(metricName, - annotation.eventType() == null ? - "requests" : annotation.eventType(), - annotation.rateUnit() == null ? - TimeUnit.SECONDS : annotation.rateUnit()); + final MetricName name = MetricName.forExceptionMeteredMethod(method.getDeclaringResource() + .getResourceClass(), + method.getMethod(), + annotation); + final Meter meter = registry.newMeter(name, annotation.eventType(), annotation.rateUnit()); dispatcher = new ExceptionMeteredRequestDispatcher(dispatcher, meter, annotation.cause()); } return dispatcher; } - }