Issue #65: Provide distribution stats for HashedWheelTimer

First cut at implementing a generic abstraction layer for pluggable
metrics providers. This first cut is closely modeled after Yammer
Metrics. It remains to be seen if it is indeed flexibel enough to
support other providers.
Provide a default implementation of this new abstraction layer
based on Yammer Metrics.
Support pluggable Monitoring Providers using Java 6's ServiceLoader.
Use this new abstraction layer to provide stats on (a) number of
Timeouts executed per second and (b) distribution of absolute
deviation between scheduled and actual Timeout execution time in
HashedWheelTimer.
 * Interface ValueDistributionMonitor, a monitor for histograms.
 * Interface EventRateMonitor, a monitor for measuring the rate per time
   unit of specific events.
 * Interface ValueMonitor, a monitor for tracking an arbitrary datum's
   current value
 * Interface CounterMonitor, a monitor for incrementing/decrementing a
   long value
 * Interface MonitorRegistry, a registry for monitors that serves as the
   interface between Netty and concrete metrics providers as e.g. Yammer
   Metrics.
 * Interface MonitorRegistryFactory, to be implemented by metrics
   providers.
 * Document how to use Netty's new monitoring support in javadocs for
   package io.netty.monitor.
This commit is contained in:
Olaf Bergner 2012-09-30 22:23:14 +02:00
parent 3bc330d477
commit ddd0734f43
31 changed files with 2187 additions and 11 deletions

View File

@ -54,7 +54,7 @@
</profiles> </profiles>
<dependencies> <dependencies>
<!-- The example depends on all modules either directly or transitively --> <!-- The example depends on (almost) all modules either directly or transitively -->
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>netty-example</artifactId> <artifactId>netty-example</artifactId>
@ -62,6 +62,14 @@
<scope>compile</scope> <scope>compile</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- The only module netty-example does NOT depend on -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-metrics-yammer</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- Add optional dependencies explicitly to avoid Javadoc warnings and errors. --> <!-- Add optional dependencies explicitly to avoid Javadoc warnings and errors. -->
<dependency> <dependency>
<groupId>com.google.protobuf</groupId> <groupId>com.google.protobuf</groupId>
@ -296,12 +304,14 @@
-link http://www.slf4j.org/apidocs/ -link http://www.slf4j.org/apidocs/
-link http://commons.apache.org/logging/commons-logging-1.1.1/apidocs/ -link http://commons.apache.org/logging/commons-logging-1.1.1/apidocs/
-link http://logging.apache.org/log4j/1.2/apidocs/ -link http://logging.apache.org/log4j/1.2/apidocs/
-link http://metrics.codahale.com/maven/apidocs/
-group "Low-level data representation" io.netty.buffer* -group "Low-level data representation" io.netty.buffer*
-group "Central interface for all I/O operations" io.netty.channel* -group "Central interface for all I/O operations" io.netty.channel*
-group "Client &amp; Server bootstrapping utilities" io.netty.bootstrap* -group "Client &amp; Server bootstrapping utilities" io.netty.bootstrap*
-group "Reusable I/O event interceptors" io.netty.handler* -group "Reusable I/O event interceptors" io.netty.handler*
-group "Miscellaneous" io.netty.logging*:io.netty.util* -group "Miscellaneous" io.netty.logging*:io.netty.util*:io.netty.monitor:io.netty.monitor.spi
-group "Yammer monitoring support" io.netty.monitor.yammer*
-sourceclasspath ${project.build.outputDirectory} -sourceclasspath ${project.build.outputDirectory}
-nopackagediagram -nopackagediagram

View File

@ -0,0 +1,82 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor;
/**
* <p>
* A simple monitor that increments and/or decrements a {@code long} value.
* </p>
* <p>
* <strong>DISCLAIMER</strong> This interface is heavily based on <a
* href="http://metrics.codahale.com/">Yammer's</a>
* {@link com.yammer.metrics.core.Counter Counter}.
* </p>
*/
public interface CounterMonitor {
/**
* Null object.
*/
CounterMonitor NOOP = new CounterMonitor() {
@Override
public void reset() {
}
@Override
public void inc(long delta) {
}
@Override
public void inc() {
}
@Override
public void decr(long delta) {
}
@Override
public void decr() {
}
};
/**
* Increment this counter by 1.
*/
void inc();
/**
* Increment this counter by the supplied {@code delta}.
* @param delta The delta to apply
*/
void inc(long delta);
/**
* Decrement this counter by 1.
*/
void decr();
/**
* Decrement this counter by the supplied {@code delta}.
* @param delta The delta to apply
*/
void decr(long delta);
/**
* Reset this counter to its initial state.
*/
void reset();
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor;
/**
* <p>
* Record the rate which an event occurs at.
* </p>
* <p>
* <strong>DISCLAIMER</strong> This interface is heavily based on <a
* href="http://metrics.codahale.com/">Yammer's</a>
* {@link com.yammer.metrics.core.Meter Meter}.
* </p>
*/
public interface EventRateMonitor {
/**
* Null object.
*/
EventRateMonitor NOOP = new EventRateMonitor() {
@Override
public void events(final long count) {
}
@Override
public void event() {
}
};
/**
* Record occurrence of one event.
*/
void event();
/**
* Record {@code count} event occurrences.
* @param count
*/
void events(long count);
}

View File

@ -0,0 +1,257 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor;
/**
* <p>
* Represents a {@code Monitor}'s unique name. This name is composed of
* <ol>
* <li>a {@code group}, an arbitrary name for a set of logically related
* {@code Monitors}, e.g. "network";</li>
* <li>a {@code type}, an arbitrary string identifying a {@code Monitor}'s
* {@code type}, commonly denoting the resource to be monitored, e.g.
* "client-connection";</li>
* <li>a {@code name}, an arbitrary string identifying what is actually
* monitored, e.g. "bytes-per-second"; and</li>
* <li>an {@code instance} (optional), an arbitrary string identifying the exact
* resource instance to be monitored, in case we aren't dealing with a singleton
* resource, e.g. "client-connection#67AF4".</li>
* </ol>
* </p>
* <p>
* <strong>DISCLAIMER</strong> This class is heavily based on <a
* href="http://metrics.codahale.com/">Yammer's</a>
* {@link com.yammer.metrics.core.MetricName MetricName}.
* </p>
*/
public final class MonitorName {
private final String group;
private final String type;
private final String name;
private final String instance;
/**
* Create a new {@code MonitorName}, using the supplied
* {@code monitoredClass}'s {@code package name} as its {@link #getGroup()
* group}, the {@code monitoredClass}'s {@code simple name} as its
* {@link #getType()} and the supplied {@code name} as its
* {@link #getName() name}.
* @param monitoredClass The class to be monitored, i.e. a class that
* represents a resource whose statistics we are interested in
* @param name Our new {@code MonitorName}'s {@link #getName() name}
* @throws NullPointerException If either {@code monitoredClass} or
* {@code name} is {@code null}
*/
public MonitorName(final Class<?> monitoredClass, final String name) {
this(monitoredClass.getPackage() != null ? monitoredClass.getPackage().getName() : "", monitoredClass
.getSimpleName().replaceAll("\\$$", ""), name, null);
}
/**
* Create a new {@code MonitorName}, using the supplied
* {@code monitoredClass}'s {@code package name} as its {@link #getGroup()
* group}, the {@code monitoredClass}'s {@code simple name} as its
* {@link #getType()}, the supplied {@code name} as its {@link #getName()
* name} and the supplied {@code instance} as its {@link #getInstance()
* instance}.
* @param monitoredClass The class to be monitored, i.e. a class that
* represents a resource whose statistics we are interested in
* @param name Our new {@code MonitorName}'s {@link #getName() name}
* @param instance Our new {@code MonitorName}'s {@link #getInstance()
* instance}
* @throws NullPointerException If either {@code monitoredClass} or
* {@code name} is {@code null}
*/
public MonitorName(final Class<?> monitoredClass, final String name, final String instance) {
this(monitoredClass.getPackage().getName(), monitoredClass.getSimpleName(), name, instance);
}
/**
* Create a new {@code MonitorName} out of the supplied {@code group},
* {@code type} and {@code name}.
* @param group Our new {@code MonitorName}'s {@link #getGroup() group}
* @param type Our new {@code MonitorName}'s {@link #getType() type}
* @param name Our new {@code MonitorName}'s {@link #getName() name}
* @throws NullPointerException If one of {@code group}, {@code type} and
* {@code name} is {@code null}
*/
public MonitorName(final String group, final String type, final String name) {
this(group, type, name, null);
}
/**
* Create a new {@code MonitorName} out of the supplied {@code group},
* {@code type}, {@code name} and {@code instance}
* @param group Our new {@code MonitorName}'s {@link #getGroup() group}
* @param type Our new {@code MonitorName}'s {@link #getType() type}
* @param name Our new {@code MonitorName}'s {@link #getName() name}
* @param instance Our new {@code MonitorName}'s {@link #getInstance()
* instance}
* @throws NullPointerException If one of {@code group}, {@code type} and
* {@code name} is {@code null}
*/
public MonitorName(final String group, final String type, final String name, final String instance) {
if (group == null) {
throw new NullPointerException("group");
}
if (type == null) {
throw new NullPointerException("type");
}
if (name == null) {
throw new NullPointerException("name");
}
this.group = group;
this.type = type;
this.name = name;
this.instance = instance;
}
/**
* Returns a copy of this {@code MonitorName} with its
* {@link #getInstance() instance} field replaced by the supplied
* {@code instance}. Serves to support a poor man's templating mechanism for
* {@code MonitorNames}.
* @param instance The instance to be used in the {@code MonitorName}
* returned by this method
* @return A copy of this {@code MonitorName} with its
* {@link #getInstance() instance} field replaced by the supplied
* {@code instance}
* @throws NullPointerException If {@code instance} is {@code null}
*/
public MonitorName ofInstance(final String instance) {
if (instance == null) {
throw new NullPointerException("instance");
}
if (instance.equals(this.instance)) {
return this;
}
return new MonitorName(this.group, this.type, this.name, instance);
}
/**
* This {@code MonitorName}'s {@code group}, an arbitrary name for a set of
* logically related {@code Monitors}, e.g. "network".
* @return The group, an arbitrary name for a set of logically related
* {@code Monitors}
*/
public String getGroup() {
return group;
}
/**
* This {@code MonitorName}'s {@code type}, an arbitrary string identifying
* a {@code Monitor}'s {@code type}, commonly denoting the resource to be
* monitored, e.g. "client-connection".
* @return The type, an arbitrary string identifying a {@code Monitor}'s
* {@code type}, commonly denoting the resource to be monitored
*/
public String getType() {
return type;
}
/**
* This {@code MonitorName}'s {@code name}, an arbitrary string identifying
* what is actually monitored, e.g. "bytes-per-second".
* @return The name, an arbitrary string identifying what is actually
* monitored
*/
public String getName() {
return name;
}
/**
* This {@code MonitorName}'s {@code instance} (optional), an arbitrary
* string identifying the exact resource instance to be monitored, in case
* we aren't dealing with a singleton resource, e.g.
* "client-connection#67AF4".
* @return The instance (optional), an arbitrary string identifying the
* exact resource instance to be monitored, in case we aren't
* dealing with a singleton resource
*/
public String getInstance() {
return instance;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((group == null) ? 0 : group.hashCode());
result = prime * result + ((instance == null) ? 0 : instance.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MonitorName other = (MonitorName) obj;
if (group == null) {
if (other.group != null) {
return false;
}
} else if (!group.equals(other.group)) {
return false;
}
if (instance == null) {
if (other.instance != null) {
return false;
}
} else if (!instance.equals(other.instance)) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
if (type == null) {
if (other.type != null) {
return false;
}
} else if (!type.equals(other.type)) {
return false;
}
return true;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return this.instance != null ? "Monitor(" + group + "/" + type + "/" + name + "/" + instance + ")" : "Monitor("
+ group + "/" + type + "/" + name + ")";
}
}

View File

@ -0,0 +1,148 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor;
import io.netty.monitor.spi.MonitorProvider;
import io.netty.monitor.spi.MonitorRegistryFactory;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* <p>
* Represents all {@link MonitorRegistry MonitorRegistries} that can be
* constructed by {@link MonitorRegistryFactory MonitorRegistryFactories} loaded
* using Java 6's {@link ServiceLoader}.
* </p>
* <p>
* A {@code MonitorRegistryFactory} that wishes to contribute a
* {@code MonitorRegistry} via {@code MonitorRegistries} needs to
* <ol>
* <li>have a no-args default constructor, and</li>
* <li>register itself - its fully qualified class name - in
* {@code META-INF/services/io.netty.monitor.spi.MonitorRegistryFactory}.</li>
* </ol>
* </p>
*/
public final class MonitorRegistries implements Iterable<MonitorRegistry> {
/**
* Return <em>the</em> singleton {@code MonitorRegistries} instance.
* @return <em>The</em> singleton {@code MonitorRegistries} instance
*/
public static MonitorRegistries instance() {
return Holder.INSTANCE;
}
private static final class Holder {
private static final MonitorRegistries INSTANCE = new MonitorRegistries();
}
private static final ServiceLoader<MonitorRegistryFactory> FACTORIES = ServiceLoader
.load(MonitorRegistryFactory.class);
/**
* Create a new {@link MonitorRegistry} that supports the supplied
* {@link MonitorProvider provider}.
* @param provider The {@link MonitorProvider provider} we are interested in
* @return A {@link MonitorRegistry} implemented by the supplied
* {@link MonitorProvider provider}
* @throws NullPointerException If {@code provider} is {@code null}
* @throws IllegalArgumentException If no {@code MonitorRegistry} matching
* the given {@link MonitorProvider provider} could be found
*/
public MonitorRegistry forProvider(final MonitorProvider provider) {
if (provider == null) {
throw new NullPointerException("provider");
}
for (final MonitorRegistryFactory candidate : FACTORIES) {
if (candidate.provider().equals(provider)) {
return candidate.newMonitorRegistry();
}
}
throw new IllegalArgumentException("Could not find MonitorRegistryFactory by provider " + provider
+ " among the set of registered MonitorRegistryFactories");
}
/**
* <p>
* Look up and return <em>the</em> uniquely determined
* {@link MonitorRegistry} implementation. This method will work in the
* standard situation where exactly one {@link MonitorRegistryFactory} is
* registered in
* {@code META-INF/services/io.netty.monitor.spi.MonitorRegistryFactory}.
* Otherwise, if either none or more than one such provider is found on the
* classpath, it will throw an {@code IllegalStateException}.
* </p>
* @return <em>The</em> uniquely determined {@link MonitorRegistry}
* implementation
* @throws IllegalStateException If either none or more that one
* {@link MonitorRegistryFactor} provider was found on the
* classpath
*/
public MonitorRegistry unique() {
final Iterator<MonitorRegistry> registries = iterator();
if (!registries.hasNext()) {
throw new IllegalStateException("Could not find any MonitorRegistryFactories on the classpath - "
+ "implementations need to be registered in META-INF/services/"
+ MonitorRegistryFactory.class.getName());
}
final MonitorRegistry candidate = registries.next();
if (registries.hasNext()) {
throw new IllegalStateException("Found more than one MonitorRegistryFactory on the classpath - "
+ "check if there is more than one implementation registered in META-INF/services/"
+ MonitorRegistryFactory.class.getName());
}
return candidate;
}
/**
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<MonitorRegistry> iterator() {
return new MonitorRegistryIterator(FACTORIES.iterator());
}
private final class MonitorRegistryIterator implements Iterator<MonitorRegistry> {
private final Iterator<MonitorRegistryFactory> factories;
private MonitorRegistryIterator(final Iterator<MonitorRegistryFactory> factories) {
this.factories = factories;
}
@Override
public boolean hasNext() {
return this.factories.hasNext();
}
@Override
public MonitorRegistry next() {
return this.factories.next().newMonitorRegistry();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Removing a MonitorRegistry is not supported");
}
}
private MonitorRegistries() {
// Singleton
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor;
import java.util.concurrent.TimeUnit;
/**
* <p>
* A factory for {@code Monitors}. Implementations are expected to keep a
* reference to each created {@code Monitor} in order to provide additional
* services, e.g. publish metrics fed by those {@code Monitors} via {@code JMX},
* {@code HTTP}.
* </p>
*/
public interface MonitorRegistry {
/**
* Null object.
*/
MonitorRegistry NOOP = NoopMonitorRegistry.INSTANCE;
/**
* Create a new {@link ValueDistributionMonitor} having the supplied
* {@link MonitorName monitorName}.
* @param monitorName The new {@link ValueDistributionMonitor}'s
* {@link MonitorName}
* @return A new {@link ValueDistributionMonitor} having the supplied
* {@link MonitorName monitorName}
*/
ValueDistributionMonitor newValueDistributionMonitor(MonitorName monitorName);
/**
* Create a new {@link EventRateMonitor} having the supplied
* {@link MonitorName monitorName}.
* @param monitorName The new {@link EventRateMonitor}'s {@link MonitorName}
* @param rateUnit The {@link TimeUnit resolution} to measure our event rate
* at
* @return A new {@link EventRateMonitor} having the supplied
* {@link MonitorName monitorName} and {@link TimeUnit rateUnit}
*/
EventRateMonitor newEventRateMonitor(MonitorName monitorName, TimeUnit rateUnit);
/**
* Register a new {@link ValueMonitor} for a datum of type {@code T}, having
* the supplied {@link MonitorName monitorName}.
* @param monitorName The new {@link ValueMonitor}'s {@link MonitorName}
* @param valueMonitor The {@link ValueMonitor} to register
* @return The {@link ValueMonitor} passed in
*/
<T> ValueMonitor<T> registerValueMonitor(MonitorName monitorName, ValueMonitor<T> valueMonitor);
/**
* Create a new {@link CounterMonitor} having the supplied
* {@link MonitorName monitorName}.
* @param monitorName The new {@link CounterMonitor}'s {@link MonitorName}
* @return A new {@link CounterMonitor} having the supplied
* {@link MonitorName monitorName}
*/
CounterMonitor newCounterMonitor(MonitorName monitorName);
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor;
import java.util.concurrent.TimeUnit;
/**
* <p>
* A {@link MonitorRegistry} that creates noop {@code Monitors}. Serves as a <a
* href="http://en.wikipedia.org/wiki/Null_Object_pattern">Null Object</a>.
* </p>
*/
final class NoopMonitorRegistry implements MonitorRegistry {
static final NoopMonitorRegistry INSTANCE = new NoopMonitorRegistry();
/**
* @see io.netty.monitor.MonitorRegistry#newValueDistributionMonitor(io.netty.monitor.MonitorName)
*/
@Override
public ValueDistributionMonitor newValueDistributionMonitor(final MonitorName monitorName) {
return ValueDistributionMonitor.NOOP;
}
/**
* @see io.netty.monitor.MonitorRegistry#newEventRateMonitor(io.netty.monitor.MonitorName,
* java.util.concurrent.TimeUnit)
*/
@Override
public EventRateMonitor newEventRateMonitor(final MonitorName monitorName, final TimeUnit rateUnit) {
return EventRateMonitor.NOOP;
}
/**
* @see io.netty.monitor.MonitorRegistry#registerValueMonitor(io.netty.monitor.MonitorName,
* io.netty.monitor.ValueMonitor)
*/
@Override
public <T> ValueMonitor<T> registerValueMonitor(final MonitorName monitorName, final ValueMonitor<T> valueMonitor) {
return valueMonitor;
}
/**
* @see io.netty.monitor.MonitorRegistry#newCounterMonitor(io.netty.monitor.MonitorName)
*/
@Override
public CounterMonitor newCounterMonitor(final MonitorName monitorName) {
return CounterMonitor.NOOP;
}
private NoopMonitorRegistry() {
// Singleton
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor;
/**
* <p>
* A monitor that tracks a value's distribution. The value to track is
* represented by a {@code long}.
* </p>
* <p>
* <strong>DISCLAIMER</strong> This interface is heavily based on <a
* href="http://metrics.codahale.com/">Yammer's</a>
* {@link com.yammer.metrics.core.Histogram Histogram}.
* </p>
*/
public interface ValueDistributionMonitor {
/**
* Null object.
*/
ValueDistributionMonitor NOOP = new ValueDistributionMonitor() {
@Override
public void update(final long value) {
}
@Override
public void reset() {
}
};
/**
* Clear this monitor, resetting it to its base state.
*/
void reset();
/**
* Record {@code value}.
* @param value
*/
void update(long value);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor;
/**
* <p>
* A monitor that tracks a datum's value. The datum to track may be of arbitrary
* type.
* </p>
* <p>
* <strong>DISCLAIMER</strong> This interface is heavily based on <a
* href="http://metrics.codahale.com/">Yammer's</a>
* {@link com.yammer.metrics.core.Gauge Gauge}.
* </p>
*/
public interface ValueMonitor<T> {
/**
* Return our monitored datum's current value.
* @return Our monitored datum's current value
*/
T currentValue();
}

View File

@ -0,0 +1,165 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* <h2>Monitoring support in Netty</h2>
* <p>
* <h3>Introduction</h3> <br/>
* In this package, Netty provides a small framework for gathering statistics -
* simple counters, gauges, histograms - on how various Netty components
* perform. Note that this package focuses on <em>gathering</em> measurements.
* The task of actually <em>aggregating</em> those measurements into meaningful
* statistics is left to pluggable {@link io.netty.monitor.spi.MonitorProvider
* MonitorProviders}.
* </p>
* <p>
* <h3>Supported Monitors</h3> <br/>
* In its current incarnation, Netty's monitoring framework supports
* <ul>
* <li>
* {@link io.netty.monitor.CounterMonitor CounterMonitors} - increment and
* decrement a {@code long} value, e.g. <em>total number of bytes received on a
* {@link io.netty.channel.Channel Channel}</em>;</li>
* <li>
* {@link io.netty.monitor.ValueMonitor ValueMonitors} - record an arbitrary
* datum's current value, e.g. <em>overall number of
* {@link io.netty.channel.Channel Channels}</em>;</li>
* <li>
* {@link io.netty.monitor.ValueDistributionMonitor
* ValueDistributionMonitors} - track a value's distribution, e.g.
* <em>size in bytes of incoming PDUs</em>;</li>
* <li>
* {@link io.netty.monitor.EventRateMonitor EventRateMonitors} - track the
* rate which an event occurs at, e.g. <em>incoming PDUs per second</em>.</li>
* </ul>
* </p>
* <p>
* <h3>Netty resources providing monitoring support</h3> <br/>
* As of today, the following Netty resources offer monitoring support out of
* the box:
* <ul>
* <li>
* {@link io.netty.util.HashedWheelTimer HashedWheelTimer}
* <ul>
* <li>track distribution of deviation between scheduled and actual
* {@link io.netty.util.Timeout Timeout} execution time, i.e. how accurate
* {@code HashedWheelTimer} is;</li>
* <li>track number of {@link io.netty.util.Timeout Timeout}s executed per
* second, i.e. {@code HashedWheelTimer}'s throughput.</li>
* </ul>
* </li>
* </ul>
* This list is expected to expand over time.
* </p>
* <p>
* <h3>Design</h3> <br/>
* As a rule, Netty refrains from introducing dependencies on third-party
* libraries as much as possible. When designing its monitoring support we
* therefore faced the choice between either implementing our own fully-fledged
* metrics subsystem, capable of efficiently computing histograms and related
* statistics, or to provide an abstraction layer over third-party libraries.
* Given (a) that writing an <em>efficient</em> - especially in terms of memory
* consumption - statistics library is a non-trivial task and (b) that many
* organizations standardize on a specific statistics library, integrating it
* into their tool chain, we chose the latter option. Essentially, arbitrary
* statistics libraries may be <em>plugged in</em>.
* </p>
* <p>
* To that end, Netty's monitoring subsystem defines an
* {@link io.netty.monitor.spi <em>SPI</em>} - <strong>S</strong>ervice
* <strong>P</strong>rovider <strong>I</strong>nterface - that needs to be
* implemented by each concrete statistics provider. Netty ships with a
* {@link io.netty.monitor.yammer default implementation} based on the excellent
* <a href="http://metrics.codahale.com">Yammer Metrics</a> library. Central to
* this <em>SPI</em> is the interface
* {@link io.netty.monitor.spi.MonitorRegistryFactory MonitorRegistryFactory},
* an implementation of which has to be provided by each metrics provider. It is
* responsible for creating a {@link io.netty.monitor.MonitorRegistry
* MonitorRegistry}, your entry point into Netty's monitoring support.
* </p>
* <p>
* <h3>Usage</h3> <br/>
* When utilizing Netty's monitoring support, you need to obtain a reference to
* a {@link io.netty.monitor.MonitorRegistry MonitorRegistry}. It is through
* this that you - either directly or, in the case of e.g.
* {@link io.netty.util.HashedWheelTimer HashedWheelTimer}, indirectly - create
* one or several of the supported monitors, e.g.
* {@link io.netty.monitor.ValueMonitor ValueMonitor}.
* </p>
* <p>
* So how do you obtain a reference to a {@code MonitorRegistry}? In one of two
* ways:
* </p>
* <p>
* <h4>1. Using Java's Service Loader support</h4> <br/>
* This approach works whenever our desired monitoring provider registers its
* {@link io.netty.montior.spi.MonitorRegistryFactory MonitorRegistryFactory}
* implementation in a file called
* {@code META-INF/services/io.netty.monitor.spi.MonitorRegistryFactory} located
* on the classpath, typically within a jar containing the implementation
* proper. In this case Java 6's {@link java.util.ServiceLoader ServiceLoader}
* will be able to instantiate that {@code MonitorRegistryFactory}, which in
* turn creates your {@code MonitorRegistry}. It goes without saying that
* Netty's {@code Yammer}-based default monitoring provider supports this
* approach.
* </p>
* <p>
* To ease this process Netty provides
* {@link io.netty.monitor.MonitorRegistries MonitorRegistries}, a convenience
* class that locates all {@code MonitorRegistryFactories} on the classpath and
* which may be asked for a {@code MonitorRegistry}. In the standard case where
* only one such provider exists, this amounts to:
*
* <pre>
* final MonitorRegistry myMonitorRegistry =
* MonitorRegistries.instance().{@link io.netty.monitor.MonitorRegistries#unique() unique()};
* final {@link io.netty.monitor.ValueMonitor ValueMonitor} overallNumberOfChannels =
* myMonitorRegistry.newValueDistributionMonitor(monitorName);
* ...
* </pre>
*
* This approach may be the most easy to use. As a downside, you relinquish
* control over how to instantiate your {@code MonitorRegistry}. Some use cases
* may not be amenable to this approach.
* </p>
* <p>
* <h4>2. Directly instantiating a {@code MonitorRegistry}</h4> <br/>
* Of course, nothing keeps you from directly instantiating your desired
* {@code MonitorRegistry}, and this may well be the most flexible approach:
*
* <pre>
* final MyMetricsProvider myMetricsProvider = new MyMetricsProvider();
* final MonitorRegistry myMonitorRegistry = new MyGrandMonitorRegistry(myMetricsProvider);
* final {@link io.netty.monitor.ValueMonitor ValueMonitor} overallNumberOfChannels =
* myMonitorRegistry.newValueDistributionMonitor(monitorName);
* ...
* </pre>
*
* Obviously, instantiating your {@code MonitorRegistry} may thus be delegated
* to your DI-container of choice, i.e. <a
* href="http://www.springsource.org/spring-framework">Spring</a>, <a
* href="http://code.google.com/p/google-guice/">Guice</a> or <a
* href="http://seamframework.org/Weld">Weld</a>.
* </p>
* <p>
* <strong>DISCLAIMER</strong> It should be noted that Netty's monitoring support
* was heavily inspired by <a href="http://codahale.com/">Coda Hale's</a>
* excellent <a href="http://metrics.codahale.com">Yammer Metrics</a> library.
* </p>
* @apiviz.hidden
*/
package io.netty.monitor;

View File

@ -0,0 +1,112 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.spi;
import java.io.Serializable;
/**
* <p>
* Simple value class that identifies a monitoring/metrics provider like e.g. <a
* href="">Yammer</a> by name.
* </p>
*/
public final class MonitorProvider implements Serializable, Comparable<MonitorProvider> {
private static final long serialVersionUID = -6549490566242173389L;
/**
* Create a new {@code MonitorProvider} instance having the supplied
* {@code name}.
* @param name The new {@code MonitorProvider}'s {@link #getName() name}.
* @return A new {@code MonitorProvider} instance having the supplied
* {@code name}
*/
public static MonitorProvider named(final String name) {
return new MonitorProvider(name);
}
private final String name;
private MonitorProvider(final String name) {
if (name == null) {
throw new NullPointerException("name");
}
if (name.length() < 1) {
throw new IllegalArgumentException("Argument 'name' must not be blank");
}
this.name = name;
}
/**
* This {@code MonitorProvider}'s unique name.
* @return This {@code MonitorProvider}'s unique name
*/
public String getName() {
return name;
}
/**
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(final MonitorProvider o) {
return this.name.compareTo(o.name);
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MonitorProvider other = (MonitorProvider) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "MonitorProvider(" + name + ")";
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.spi;
import io.netty.monitor.MonitorRegistry;
/**
* <p>
* A {@link MonitorProvider provider}-specific factory for
* {@link MonitorRegistry MonitorRegistries}.
* </p>
*/
public interface MonitorRegistryFactory {
/**
* This {@code MonitorRegistryFactory}'s {@link MonitorProvider provider}.
* @return This {@code MonitorRegistryFactory}'s {@link MonitorProvider
* provider}
*/
MonitorProvider provider();
/**
* Create a new {@link MonitorRegistry}.
* @return A new {@link MonitorRegistry}
*/
MonitorRegistry newMonitorRegistry();
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* <p>
* Defines an <em>SPI</em> - <em>S</em>ervice <em>P</em>rovider <em>I</em>nterface - for
* {@link io.netty.monitor.spi.MonitorProvider MonitorProviders}.
* </p>
*
* @apiviz.hidden
*/
package io.netty.monitor.spi;

View File

@ -17,6 +17,10 @@ package io.netty.util;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
import io.netty.monitor.ValueDistributionMonitor;
import io.netty.monitor.EventRateMonitor;
import io.netty.monitor.MonitorName;
import io.netty.monitor.MonitorRegistry;
import io.netty.util.internal.DetectionUtil; import io.netty.util.internal.DetectionUtil;
import io.netty.util.internal.SharedResourceMisuseDetector; import io.netty.util.internal.SharedResourceMisuseDetector;
@ -83,6 +87,11 @@ public class HashedWheelTimer implements Timer {
private static final SharedResourceMisuseDetector misuseDetector = private static final SharedResourceMisuseDetector misuseDetector =
new SharedResourceMisuseDetector(HashedWheelTimer.class); new SharedResourceMisuseDetector(HashedWheelTimer.class);
private static final MonitorName TIMEOUT_EXPIRATION_TIME_DEVIATION_MN = new MonitorName(HashedWheelTimer.class,
"timeout-expiration-time-deviation");
private static final MonitorName TIMEOUTS_PER_SECOND_MN = new MonitorName(HashedWheelTimer.class,
"timeouts-per-second");
private final Worker worker = new Worker(); private final Worker worker = new Worker();
final Thread workerThread; final Thread workerThread;
final AtomicInteger workerState = new AtomicInteger(); // 0 - init, 1 - started, 2 - shut down final AtomicInteger workerState = new AtomicInteger(); // 0 - init, 1 - started, 2 - shut down
@ -94,6 +103,10 @@ public class HashedWheelTimer implements Timer {
final ReadWriteLock lock = new ReentrantReadWriteLock(); final ReadWriteLock lock = new ReentrantReadWriteLock();
volatile int wheelCursor; volatile int wheelCursor;
// Monitoring this instance
final ValueDistributionMonitor timeoutExpirationTimeDeviation;
final EventRateMonitor timeoutsPerSecond;
/** /**
* Creates a new timer with the default thread factory * Creates a new timer with the default thread factory
* ({@link Executors#defaultThreadFactory()}), default tick duration, and * ({@link Executors#defaultThreadFactory()}), default tick duration, and
@ -110,6 +123,8 @@ public class HashedWheelTimer implements Timer {
* *
* @param tickDuration the duration between tick * @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration} * @param unit the time unit of the {@code tickDuration}
* @throws NullPointerException if {@code unit} is {@code null}
* @throws IllegalArgumentException if {@code tickDuration} is <= 0
*/ */
public HashedWheelTimer(long tickDuration, TimeUnit unit) { public HashedWheelTimer(long tickDuration, TimeUnit unit) {
this(Executors.defaultThreadFactory(), tickDuration, unit); this(Executors.defaultThreadFactory(), tickDuration, unit);
@ -122,6 +137,8 @@ public class HashedWheelTimer implements Timer {
* @param tickDuration the duration between tick * @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration} * @param unit the time unit of the {@code tickDuration}
* @param ticksPerWheel the size of the wheel * @param ticksPerWheel the size of the wheel
* @throws NullPointerException if {@code unit} is {@code null}
* @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0
*/ */
public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel) { public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel) {
this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel); this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel);
@ -134,6 +151,7 @@ public class HashedWheelTimer implements Timer {
* @param threadFactory a {@link ThreadFactory} that creates a * @param threadFactory a {@link ThreadFactory} that creates a
* background {@link Thread} which is dedicated to * background {@link Thread} which is dedicated to
* {@link TimerTask} execution. * {@link TimerTask} execution.
* @throws NullPointerException if {@code threadFactory} is {@code null}
*/ */
public HashedWheelTimer(ThreadFactory threadFactory) { public HashedWheelTimer(ThreadFactory threadFactory) {
this(threadFactory, 100, TimeUnit.MILLISECONDS); this(threadFactory, 100, TimeUnit.MILLISECONDS);
@ -147,6 +165,8 @@ public class HashedWheelTimer implements Timer {
* {@link TimerTask} execution. * {@link TimerTask} execution.
* @param tickDuration the duration between tick * @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration} * @param unit the time unit of the {@code tickDuration}
* @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null}
* @throws IllegalArgumentException if {@code tickDuration} is <= 0
*/ */
public HashedWheelTimer( public HashedWheelTimer(
ThreadFactory threadFactory, long tickDuration, TimeUnit unit) { ThreadFactory threadFactory, long tickDuration, TimeUnit unit) {
@ -162,10 +182,87 @@ public class HashedWheelTimer implements Timer {
* @param tickDuration the duration between tick * @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration} * @param unit the time unit of the {@code tickDuration}
* @param ticksPerWheel the size of the wheel * @param ticksPerWheel the size of the wheel
* @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null}
* @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0
*/ */
public HashedWheelTimer( public HashedWheelTimer(
ThreadFactory threadFactory, ThreadFactory threadFactory,
long tickDuration, TimeUnit unit, int ticksPerWheel) { long tickDuration, TimeUnit unit, int ticksPerWheel) {
this(threadFactory, tickDuration, unit, ticksPerWheel, MonitorRegistry.NOOP);
}
/**
* Creates a new timer with {@link io.netty.monitor monitoring support}
* enabled. The new timer instance will monitor
* <ul>
* <li>
* the distribution of deviation between scheduled and actual
* {@link Timeout timeout} execution, i.e. how accurate this timer is; and
* </li>
* <li>
* the rate of {@link Timeout timeout} executions per second.
* </li>
* </ul>
*
* @param threadFactory a {@link ThreadFactory} that creates a
* background {@link Thread} which is dedicated to
* {@link TimerTask} execution.
* @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration}
* @param ticksPerWheel the size of the wheel
* @param monitorRegistry the {@link MonitorRegistry} to use
* @throws NullPointerException
* if either of {@code threadFactory} and {@code unit}
* is {@code null}
* @throws IllegalArgumentException
* if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0
*/
public HashedWheelTimer(ThreadFactory threadFactory, long tickDuration, TimeUnit unit, int ticksPerWheel,
MonitorRegistry monitorRegistry) {
this(threadFactory, tickDuration, unit, ticksPerWheel, monitorRegistry,
TIMEOUT_EXPIRATION_TIME_DEVIATION_MN, TIMEOUTS_PER_SECOND_MN);
}
/**
* Creates a new timer with {@link io.netty.monitor monitoring support}
* enabled. The new timer instance will monitor
* <ul>
* <li>
* the distribution of deviation between scheduled and actual
* {@link Timeout timeout} execution, i.e. how accurate this timer is; and
* </li>
* <li>
* the rate of {@link Timeout timeout} executions per second.
* </li>
* </ul>
*
* @param threadFactory a {@link ThreadFactory} that creates a
* background {@link Thread} which is dedicated to
* {@link TimerTask} execution.
* @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration}
* @param ticksPerWheel the size of the wheel
* @param monitorRegistry the {@link MonitorRegistry} to use
* @param timeoutExpirationTimeDeviationMonitorName
* the {@link MonitorName name} to use for the
* {@code Monitor} that tracks the distribution of
* deviation between scheduled and actual timeout
* execution
* @param timeoutsPerSecondMonitorName
* the {@link MonitorName name} to use for the
* {@code Monitor} that tracks the rate of timeout
* executions per second
* @throws NullPointerException
* if either of {@code threadFactory}, {@code unit},
* {@code monitorRegistry},
* {@code timeoutExpirationTimeDeviationMonitorName} and
* {@code timeoutsPerSecondMonitorName} is {@code null}
* @throws IllegalArgumentException
* if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0
*/
public HashedWheelTimer(ThreadFactory threadFactory, long tickDuration, TimeUnit unit, int ticksPerWheel,
MonitorRegistry monitorRegistry, MonitorName timeoutExpirationTimeDeviationMonitorName,
MonitorName timeoutsPerSecondMonitorName) {
if (threadFactory == null) { if (threadFactory == null) {
throw new NullPointerException("threadFactory"); throw new NullPointerException("threadFactory");
@ -173,13 +270,20 @@ public class HashedWheelTimer implements Timer {
if (unit == null) { if (unit == null) {
throw new NullPointerException("unit"); throw new NullPointerException("unit");
} }
if (monitorRegistry == null) {
throw new NullPointerException("monitorRegistry");
}
if (timeoutExpirationTimeDeviationMonitorName == null) {
throw new NullPointerException("timeoutExpirationTimeDeviationMonitorName");
}
if (timeoutsPerSecondMonitorName == null) {
throw new NullPointerException("timeoutsPerSecondMonitorName");
}
if (tickDuration <= 0) { if (tickDuration <= 0) {
throw new IllegalArgumentException( throw new IllegalArgumentException("tickDuration must be greater than 0: " + tickDuration);
"tickDuration must be greater than 0: " + tickDuration);
} }
if (ticksPerWheel <= 0) { if (ticksPerWheel <= 0) {
throw new IllegalArgumentException( throw new IllegalArgumentException("ticksPerWheel must be greater than 0: " + ticksPerWheel);
"ticksPerWheel must be greater than 0: " + ticksPerWheel);
} }
// Normalize ticksPerWheel to power of two and initialize the wheel. // Normalize ticksPerWheel to power of two and initialize the wheel.
@ -190,17 +294,19 @@ public class HashedWheelTimer implements Timer {
this.tickDuration = tickDuration = unit.toMillis(tickDuration); this.tickDuration = tickDuration = unit.toMillis(tickDuration);
// Prevent overflow. // Prevent overflow.
if (tickDuration == Long.MAX_VALUE || if (tickDuration == Long.MAX_VALUE || tickDuration >= Long.MAX_VALUE / wheel.length) {
tickDuration >= Long.MAX_VALUE / wheel.length) { throw new IllegalArgumentException("tickDuration is too long: " + tickDuration + ' ' + unit);
throw new IllegalArgumentException(
"tickDuration is too long: " +
tickDuration + ' ' + unit);
} }
roundDuration = tickDuration * wheel.length; roundDuration = tickDuration * wheel.length;
workerThread = threadFactory.newThread(worker); workerThread = threadFactory.newThread(worker);
timeoutExpirationTimeDeviation =
monitorRegistry.newValueDistributionMonitor(timeoutExpirationTimeDeviationMonitorName);
timeoutsPerSecond =
monitorRegistry.newEventRateMonitor(timeoutsPerSecondMonitorName, TimeUnit.SECONDS);
// Misuse check // Misuse check
misuseDetector.increase(); misuseDetector.increase();
} }
@ -518,6 +624,8 @@ public class HashedWheelTimer implements Timer {
} }
try { try {
timeoutsPerSecond.event();
timeoutExpirationTimeDeviation.update(System.currentTimeMillis() - deadline);
task.run(this); task.run(this);
} catch (Throwable t) { } catch (Throwable t) {
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {

View File

@ -0,0 +1,44 @@
package io.netty.monitor;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import io.netty.monitor.support.SampleMonitorRegistryFactory;
import org.junit.Test;
public class MonitorRegistriesTest {
@Test
public final void instanceShouldNotReturnNull() {
assertNotNull("instance() should NEVER return null",
MonitorRegistries.instance());
}
@Test
public final void instanceShouldAlwaysReturnTheSameInstance() {
final MonitorRegistries firstInstance = MonitorRegistries.instance();
final MonitorRegistries secondInstance = MonitorRegistries.instance();
assertSame("instance() should always return the same instance",
firstInstance, secondInstance);
}
@Test
public final void forProviderShouldReturnMonitorRegistryMatchingTheSuppliedProvider() {
final MonitorRegistries objectUnderTest = MonitorRegistries.instance();
final MonitorRegistry registry = objectUnderTest
.forProvider(SampleMonitorRegistryFactory.PROVIDER);
assertSame("forProvider(" + SampleMonitorRegistryFactory.PROVIDER
+ ") should return a MonitorRegistry by the supplied provider",
SampleMonitorRegistryFactory.SampleMonitorRegistry.class,
registry.getClass());
}
@Test(expected = IllegalStateException.class)
public final void uniqueShouldThrowIllegalStateExceptionIfMoreThanOneProviderIsRegistered() {
final MonitorRegistries objectUnderTest = MonitorRegistries.instance();
objectUnderTest.unique();
}
}

View File

@ -0,0 +1,86 @@
package io.netty.monitor.support;
import io.netty.monitor.CounterMonitor;
import io.netty.monitor.EventRateMonitor;
import io.netty.monitor.MonitorName;
import io.netty.monitor.MonitorRegistry;
import io.netty.monitor.ValueDistributionMonitor;
import io.netty.monitor.ValueMonitor;
import io.netty.monitor.spi.MonitorProvider;
import io.netty.monitor.spi.MonitorRegistryFactory;
import java.util.concurrent.TimeUnit;
public class AnotherSampleMonitorRegistryFactory implements MonitorRegistryFactory {
public static final MonitorProvider PROVIDER = MonitorProvider.named("ANOTHER_SAMPLE");
@Override
public MonitorProvider provider() {
return PROVIDER;
}
@Override
public MonitorRegistry newMonitorRegistry() {
return new AnotherSampleMonitorRegistry();
}
public static final class AnotherSampleMonitorRegistry implements MonitorRegistry {
@Override
public ValueDistributionMonitor newValueDistributionMonitor(final MonitorName monitorName) {
return new ValueDistributionMonitor() {
@Override
public void update(final long value) {
}
@Override
public void reset() {
}
};
}
@Override
public EventRateMonitor newEventRateMonitor(final MonitorName monitorName, final TimeUnit rateUnit) {
return new EventRateMonitor() {
@Override
public void events(final long count) {
}
@Override
public void event() {
}
};
}
@Override
public <T> ValueMonitor<T> registerValueMonitor(MonitorName monitorName, ValueMonitor<T> valueMonitor) {
return valueMonitor;
}
@Override
public CounterMonitor newCounterMonitor(MonitorName monitorName) {
return new CounterMonitor() {
@Override
public void reset() {
}
@Override
public void inc(long delta) {
}
@Override
public void inc() {
}
@Override
public void decr(long delta) {
}
@Override
public void decr() {
}
};
}
}
}

View File

@ -0,0 +1,86 @@
package io.netty.monitor.support;
import io.netty.monitor.CounterMonitor;
import io.netty.monitor.EventRateMonitor;
import io.netty.monitor.MonitorName;
import io.netty.monitor.MonitorRegistry;
import io.netty.monitor.ValueDistributionMonitor;
import io.netty.monitor.ValueMonitor;
import io.netty.monitor.spi.MonitorProvider;
import io.netty.monitor.spi.MonitorRegistryFactory;
import java.util.concurrent.TimeUnit;
public class SampleMonitorRegistryFactory implements MonitorRegistryFactory {
public static final MonitorProvider PROVIDER = MonitorProvider.named("SAMPLE");
@Override
public MonitorProvider provider() {
return PROVIDER;
}
@Override
public MonitorRegistry newMonitorRegistry() {
return new SampleMonitorRegistry();
}
public static final class SampleMonitorRegistry implements MonitorRegistry {
@Override
public ValueDistributionMonitor newValueDistributionMonitor(final MonitorName monitorName) {
return new ValueDistributionMonitor() {
@Override
public void update(final long value) {
}
@Override
public void reset() {
}
};
}
@Override
public EventRateMonitor newEventRateMonitor(final MonitorName monitorName, final TimeUnit rateUnit) {
return new EventRateMonitor() {
@Override
public void events(final long count) {
}
@Override
public void event() {
}
};
}
@Override
public <T> ValueMonitor<T> registerValueMonitor(MonitorName monitorName, ValueMonitor<T> valueMonitor) {
return valueMonitor;
}
@Override
public CounterMonitor newCounterMonitor(MonitorName monitorName) {
return new CounterMonitor() {
@Override
public void reset() {
}
@Override
public void inc(long delta) {
}
@Override
public void inc() {
}
@Override
public void decr(long delta) {
}
@Override
public void decr() {
}
};
}
}
}

View File

@ -0,0 +1,133 @@
package io.netty.util;
import static org.junit.Assert.assertTrue;
import io.netty.monitor.CounterMonitor;
import io.netty.monitor.EventRateMonitor;
import io.netty.monitor.MonitorName;
import io.netty.monitor.MonitorRegistry;
import io.netty.monitor.ValueDistributionMonitor;
import io.netty.monitor.ValueMonitor;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
public class HashedWheelTimerMonitorTest {
@Test
public final void shouldCallValueDistributionMonitorWhenTimeoutExpires() throws InterruptedException {
final CountDownLatch eventDistributionCalled = new CountDownLatch(1);
final ValueDistributionMonitor eventDistributionRecorder = new ValueDistributionMonitor() {
@Override
public void update(final long value) {
eventDistributionCalled.countDown();
}
@Override
public void reset() {
}
};
final RecordingMonitorRegistry recordingMonitorRegistry = new RecordingMonitorRegistry(
eventDistributionRecorder, EventRateMonitor.NOOP);
final HashedWheelTimer objectUnderTest = new HashedWheelTimer(Executors.defaultThreadFactory(), 100,
TimeUnit.MILLISECONDS, 512, recordingMonitorRegistry);
objectUnderTest.newTimeout(new TimerTask() {
@Override
public void run(final Timeout timeout) throws Exception {
}
}, 1, TimeUnit.MILLISECONDS);
assertTrue("HashedWheelTimer should have called ValueDistributionMonitor when Timeout expired",
eventDistributionCalled.await(200, TimeUnit.MILLISECONDS));
}
private static class RecordingMonitorRegistry implements MonitorRegistry {
private final ValueDistributionMonitor eventDistributionMonitor;
private final EventRateMonitor eventRateMonitor;
/**
* @param eventDistributionMonitor
* @param eventRateMonitor
*/
RecordingMonitorRegistry(final ValueDistributionMonitor eventDistributionMonitor,
final EventRateMonitor eventRateMonitor) {
this.eventDistributionMonitor = eventDistributionMonitor;
this.eventRateMonitor = eventRateMonitor;
}
@Override
public ValueDistributionMonitor newValueDistributionMonitor(final MonitorName monitorName) {
return this.eventDistributionMonitor;
}
@Override
public EventRateMonitor newEventRateMonitor(final MonitorName monitorName, final TimeUnit rateUnit) {
return this.eventRateMonitor;
}
@Override
public <T> ValueMonitor<T> registerValueMonitor(MonitorName monitorName, ValueMonitor<T> valueMonitor) {
return valueMonitor;
}
@Override
public CounterMonitor newCounterMonitor(MonitorName monitorName) {
return new CounterMonitor() {
@Override
public void reset() {
}
@Override
public void inc(long delta) {
}
@Override
public void inc() {
}
@Override
public void decr(long delta) {
}
@Override
public void decr() {
}
};
}
}
@Test
public final void shouldCallEventRateMonitorWhenTimeoutExpires() throws InterruptedException {
final CountDownLatch eventRateCalled = new CountDownLatch(1);
final EventRateMonitor eventRateRecorder = new EventRateMonitor() {
@Override
public void events(final long count) {
}
@Override
public void event() {
eventRateCalled.countDown();
}
};
final RecordingMonitorRegistry recordingMonitorRegistry = new RecordingMonitorRegistry(
ValueDistributionMonitor.NOOP, eventRateRecorder);
final HashedWheelTimer objectUnderTest = new HashedWheelTimer(Executors.defaultThreadFactory(), 100,
TimeUnit.MILLISECONDS, 512, recordingMonitorRegistry);
objectUnderTest.newTimeout(new TimerTask() {
@Override
public void run(final Timeout timeout) throws Exception {
}
}, 1, TimeUnit.MILLISECONDS);
assertTrue("HashedWheelTimer should have called EventRateMonitor when Timeout expired",
eventRateCalled.await(200, TimeUnit.MILLISECONDS));
}
}

View File

@ -0,0 +1,2 @@
io.netty.monitor.support.SampleMonitorRegistryFactory
io.netty.monitor.support.AnotherSampleMonitorRegistryFactory

45
metrics-yammer/pom.xml Normal file
View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2012 The Netty Project
~
~ The Netty Project licenses this file to you under the Apache License,
~ version 2.0 (the "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at:
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
~ License for the specific language governing permissions and limitations
~ under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.netty</groupId>
<artifactId>netty-parent</artifactId>
<version>4.0.0.Alpha6-SNAPSHOT</version>
</parent>
<artifactId>netty-metrics-yammer</artifactId>
<packaging>jar</packaging>
<name>Netty/Yammer Metrics Provider</name>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<scope>compile</scope>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.yammer.metrics</groupId>
<artifactId>metrics-core</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,37 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.yammer;
import io.netty.monitor.MonitorName;
import com.yammer.metrics.core.MetricName;
/**
* <p>
* Static helper methods.
* </p>
*/
final class Utils {
static MetricName toMetricName(final MonitorName monitorName) {
return new MetricName(monitorName.getGroup(), monitorName.getType(), monitorName.getName(),
monitorName.getInstance());
}
private Utils() {
// Unused
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.yammer;
import io.netty.monitor.CounterMonitor;
import com.yammer.metrics.core.Counter;
/**
* <p>
* An {@link CounterMonitor} that delegates to a <a
* href="http://metrics.codahale.com/">Yammer</a> {@link Counter}.
* </p>
*/
class YammerCounterMonitor implements CounterMonitor {
private final Counter delegate;
/**
* @param delegate
*/
YammerCounterMonitor(final Counter delegate) {
if (delegate == null) {
throw new NullPointerException("delegate");
}
this.delegate = delegate;
}
/**
* @see io.netty.monitor.CounterMonitor#inc()
*/
@Override
public void inc() {
this.delegate.inc();
}
/**
* @see io.netty.monitor.CounterMonitor#inc(long)
*/
@Override
public void inc(final long delta) {
this.delegate.inc(delta);
}
/**
* @see io.netty.monitor.CounterMonitor#decr()
*/
@Override
public void decr() {
this.delegate.dec();
}
/**
* @see io.netty.monitor.CounterMonitor#decr(long)
*/
@Override
public void decr(final long delta) {
this.delegate.dec(delta);
}
/**
* @see io.netty.monitor.CounterMonitor#reset()
*/
@Override
public void reset() {
this.delegate.clear();
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "YammerCounterMonitor(delegate=" + delegate + ")";
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.yammer;
import io.netty.monitor.EventRateMonitor;
import com.yammer.metrics.core.Meter;
/**
* <p>
* An {@link EventRateMonitor} that delegates to a <a
* href="http://metrics.codahale.com/">Yammer</a> {@link Meter}.
* </p>
*/
class YammerEventRateMonitor implements EventRateMonitor {
private final Meter delegate;
/**
* @param delegate
*/
YammerEventRateMonitor(final Meter delegate) {
if (delegate == null) {
throw new NullPointerException("delegate");
}
this.delegate = delegate;
}
/**
* @see io.netty.monitor.EventRateMonitor#event()
* @see com.yammer.metrics.core.Meter#mark()
*/
@Override
public void event() {
this.delegate.mark();
}
/**
* @see io.netty.monitor.EventRateMonitor#events(long)
* @see com.yammer.metrics.core.Meter#mark(long)
*/
@Override
public void events(final long count) {
this.delegate.mark(count);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "YammerEventRateMonitor(delegate=" + delegate + ")";
}
}

View File

@ -0,0 +1,122 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.yammer;
import io.netty.monitor.CounterMonitor;
import io.netty.monitor.EventRateMonitor;
import io.netty.monitor.MonitorName;
import io.netty.monitor.MonitorRegistry;
import io.netty.monitor.ValueDistributionMonitor;
import io.netty.monitor.ValueMonitor;
import java.util.concurrent.TimeUnit;
import com.yammer.metrics.Metrics;
import com.yammer.metrics.core.Counter;
import com.yammer.metrics.core.Gauge;
import com.yammer.metrics.core.Histogram;
import com.yammer.metrics.core.Meter;
import com.yammer.metrics.core.MetricsRegistry;
/**
* <p>
* A {@link MonitorRegistry} that delegates to a <a
* href="http://metrics.codahale.com/">Yammer</a> {@link MetricsRegistry}.
* </p>
*/
public final class YammerMonitorRegistry implements MonitorRegistry {
private final MetricsRegistry delegate;
/**
* Constructs a {@code YammerMonitorRegistry} that delegates to
* {@code Yammer}'s {@link Metrics#defaultRegistry() default registry}.
*/
public YammerMonitorRegistry() {
this(Metrics.defaultRegistry());
}
/**
* Constructs a {@code YammerMonitorRegistry} that delegates to the supplied
* {@code Yammer} {@link MetricsRegistry delegate}.
* @param delegate The {@code Yammer} {@link MetricsRegistry} to delegate to
*/
public YammerMonitorRegistry(final MetricsRegistry delegate) {
if (delegate == null) {
throw new NullPointerException("delegate");
}
this.delegate = delegate;
}
/**
* Create a new {@link ValueDistributionMonitor} that is backed by a
* {@code Yammer} {@link Histrogram}.
* @see io.netty.monitor.MonitorRegistry#newValueDistributionMonitor(io.netty.monitor.MonitorName)
*/
@Override
public ValueDistributionMonitor newValueDistributionMonitor(final MonitorName monitorName) {
final Histogram histogram = this.delegate.newHistogram(Utils.toMetricName(monitorName), true);
return new YammerValueDistributionMonitor(histogram);
}
/**
* Create a new {@link EventRateMonitor} that is backed by a {@code Yammer}
* {@link Meter}.
* @see io.netty.monitor.MonitorRegistry#newEventRateMonitor(io.netty.monitor.MonitorName,
* java.util.concurrent.TimeUnit)
*/
@Override
public EventRateMonitor newEventRateMonitor(final MonitorName monitorName, final TimeUnit rateUnit) {
final Meter meter = this.delegate.newMeter(Utils.toMetricName(monitorName), monitorName.getName(), rateUnit);
return new YammerEventRateMonitor(meter);
}
/**
* Register the supplied {@link ValueMonitor valueMonitor}, using it
* internally to create a {@code Yammer} {@link Gauge}.
* @see io.netty.monitor.MonitorRegistry#registerValueMonitor(io.netty.monitor.MonitorName,
* io.netty.monitor.ValueMonitor)
*/
@Override
public <T> ValueMonitor<T> registerValueMonitor(final MonitorName monitorName, final ValueMonitor<T> valueMonitor) {
this.delegate.newGauge(Utils.toMetricName(monitorName), new Gauge<T>() {
@Override
public T value() {
return valueMonitor.currentValue();
}
});
return valueMonitor;
}
/**
* Create a new {@link CounterMonitor} that is backed by a {@code Yammer}
* {@link Counter}.
* @see io.netty.monitor.MonitorRegistry#newCounterMonitor(io.netty.monitor.MonitorName)
*/
@Override
public CounterMonitor newCounterMonitor(MonitorName monitorName) {
final Counter counter = this.delegate.newCounter(Utils.toMetricName(monitorName));
return new YammerCounterMonitor(counter);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "YammerMonitorRegistry(delegate=" + delegate + ")";
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.yammer;
import io.netty.monitor.spi.MonitorProvider;
public final class YammerProvider {
public static final MonitorProvider PROVIDER = MonitorProvider
.named("YAMMER");
private YammerProvider() {
// Unused
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.yammer;
import io.netty.monitor.ValueDistributionMonitor;
import com.yammer.metrics.core.Histogram;
/**
* <p>
* An {@link ValueDistributionMonitor} that delegates to a <a
* href="http://metrics.codahale.com/">Yammer</a> {@link Histogram}.
* </p>
*/
final class YammerValueDistributionMonitor implements ValueDistributionMonitor {
private final Histogram delegate;
/**
* @param delegate
*/
YammerValueDistributionMonitor(final Histogram delegate) {
if (delegate == null) {
throw new NullPointerException("delegate");
}
this.delegate = delegate;
}
/**
* @see io.netty.monitor.EventDistributionMonitor#reset()
*/
@Override
public void reset() {
this.delegate.clear();
}
/**
* @see io.netty.monitor.EventDistributionMonitor#update(long)
*/
@Override
public void update(final long value) {
this.delegate.update(value);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "YammerEventDistributionMonitor(delegate=" + delegate + ")";
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* <p>
* Provides {@link io.netty.monitor Monitor} implementations backed by
* <a href="http://metrics.codahale.com/">Yammer Metrics</a>.
* </p>
*
* @apiviz.hidden
*/
package io.netty.monitor.yammer;

View File

@ -0,0 +1,76 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.monitor.yammer.spi;
import io.netty.monitor.MonitorRegistry;
import io.netty.monitor.spi.MonitorProvider;
import io.netty.monitor.spi.MonitorRegistryFactory;
import io.netty.monitor.yammer.YammerMonitorRegistry;
import io.netty.monitor.yammer.YammerProvider;
import com.yammer.metrics.Metrics;
import com.yammer.metrics.core.MetricsRegistry;
/**
* <p>
* A {@link MonitorRegistryFactory} that produces {@link YammerMonitorRegistry
* YammerMonitorRegistries}.
* </p>
*/
public class YammerMonitorRegistryFactory implements MonitorRegistryFactory {
private final MetricsRegistry metricsRegistry;
/**
*/
public YammerMonitorRegistryFactory() {
this(Metrics.defaultRegistry());
}
/**
* @param metricsRegistry
*/
public YammerMonitorRegistryFactory(final MetricsRegistry metricsRegistry) {
if (metricsRegistry == null) {
throw new NullPointerException("metricsRegistry");
}
this.metricsRegistry = metricsRegistry;
}
/**
* @see io.netty.monitor.spi.MonitorRegistryFactory#provider()
*/
@Override
public MonitorProvider provider() {
return YammerProvider.PROVIDER;
}
/**
* @see io.netty.monitor.spi.MonitorRegistryFactory#newMonitorRegistry()
*/
@Override
public MonitorRegistry newMonitorRegistry() {
return new YammerMonitorRegistry(metricsRegistry);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "YammerMonitorRegistryFactory(metricsRegistry=" + metricsRegistry + ")";
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* <p>
* Provides a {@link io.netty.monitor.spi.MonitorRegistryFactory MonitorRegistryFactory}
* that produces {@link YammerMonitorRegistry YammerMonitorRegistries}.
* </p>
*
* @apiviz.hidden
*/
package io.netty.monitor.yammer.spi;

View File

@ -0,0 +1 @@
io.netty.monitor.yammer.spi.YammerMonitorRegistryFactory

10
pom.xml
View File

@ -69,6 +69,7 @@
<properties> <properties>
<jboss.marshalling.version>1.3.14.GA</jboss.marshalling.version> <jboss.marshalling.version>1.3.14.GA</jboss.marshalling.version>
<yammer.metrics.version>2.1.2</yammer.metrics.version>
</properties> </properties>
<modules> <modules>
@ -78,6 +79,7 @@
<module>codec-http</module> <module>codec-http</module>
<module>transport</module> <module>transport</module>
<module>handler</module> <module>handler</module>
<module>metrics-yammer</module>
<module>example</module> <module>example</module>
<module>testsuite</module> <module>testsuite</module>
<module>all</module> <module>all</module>
@ -163,6 +165,14 @@
</exclusions> </exclusions>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- Metrics providers -->
<dependency>
<groupId>com.yammer.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${yammer.metrics.version}</version>
</dependency>
<!-- Test dependencies for jboss marshalling encoder/decoder --> <!-- Test dependencies for jboss marshalling encoder/decoder -->
<dependency> <dependency>
<groupId>org.jboss.marshalling</groupId> <groupId>org.jboss.marshalling</groupId>