Add some of the metrics mentioned in #718

use single static initialization of available metrics monitor registries

* This changes the original implementation to work in a similar way to
how slf4j selects and loads an implementation.
* Uses a single static instance so intialization is done only once.
* Doesn't throw IllegalStateException if multiple implementations are
found on the classpath. It instead selects and uses the first
implementation returned by iterator()
* Class left as an iterable to keep the API the same

add yammer metrics to examples to allow them to publish metrics

publish the number of threads used in an EventLoopGroup see issue #718

* seems like the better place to put this because it sets the default
thread count if the MultithreadEventLoopGroup uses super(0,...)
* It also happens to be the common parent class amongst all the
MultiThreadedEventLoopGroup implementations
* Count is reported for
io.netty.channel.{*,.local,.socket.aio,.socket.nio}

fix cosmetic issues pointed out in pull request and updated notice.txt

see https://github.com/netty/netty/pull/780

count # of channels registered in single threaded event loop

measure how many times Selector.select return before SELECT_TIME
This commit is contained in:
Courtney Robinson 2012-11-30 06:07:26 +00:00 committed by Norman Maurer
parent bd093c4ab0
commit 3a52cc410a
7 changed files with 90 additions and 26 deletions

View File

@ -90,8 +90,10 @@ serialization API, which can be obtained at:
* HOMEPAGE:
* http://www.jboss.org/jbossmarshalling
This product optionally depends on 'SLF4J', a simple logging facade for Java,
which can be obtained at:
This product optionally depends on 'SLF4J', a simple logging facade for Java.
The monitor registries implementation is based on the approach used by SLF4J.
Slf4j can be obtained at:
* LICENSE:
* license/LICENSE.slf4j.txt (MIT License)

View File

@ -15,6 +15,8 @@
*/
package io.netty.monitor;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
import io.netty.monitor.spi.MonitorProvider;
import io.netty.monitor.spi.MonitorRegistryFactory;
@ -38,9 +40,19 @@ import java.util.ServiceLoader;
* </p>
*/
public final class MonitorRegistries implements Iterable<MonitorRegistry> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(MonitorRegistries.class);
//set of initialization states
private static final int UNINITIALIZED = 0;
private static final int ONGOING_INITIALIZATION = 1;
private static final int SUCCESSFUL_INITIALIZATION = 2;
private static final int NOP_FALLBACK_INITIALIZATION = 3;
private static int INITIALIZATION_STATE = UNINITIALIZED;
private static MonitorRegistry selectedRegistry;
/**
* Return <em>the</em> singleton {@code MonitorRegistries} instance.
*
* @return <em>The</em> singleton {@code MonitorRegistries} instance
*/
public static MonitorRegistries instance() {
@ -57,14 +69,15 @@ public final class MonitorRegistries implements Iterable<MonitorRegistry> {
/**
* 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 NullPointerException If {@code provider} is {@code null}
* @throws IllegalArgumentException If no {@code MonitorRegistry} matching
* the given {@link MonitorProvider provider} could be found
* the given {@link MonitorProvider provider} could be found
*/
public MonitorRegistry forProvider(final MonitorProvider provider) {
public static MonitorRegistry forProvider(final MonitorProvider provider) {
if (provider == null) {
throw new NullPointerException("provider");
}
@ -79,34 +92,49 @@ public final class MonitorRegistries implements Iterable<MonitorRegistry> {
/**
* <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
* Look up and return <em>the</em> a uniquely determined
* {@link MonitorRegistry} implementation. This method will select
* exactly one {@link MonitorRegistryFactory} from those 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}.
* if no implementation is found then a NOOP registry is returned.
* If multiple implementations are found then the first one returned by
* {@link #iterator()} is used and a message is logged to say which one is
* selected.
* </p>
* @return <em>The</em> uniquely determined {@link MonitorRegistry}
*
* @return <em>the</em> uniquely determined {@link MonitorRegistry}
* implementation
* @throws IllegalStateException If either none or more that one
* {@link MonitorRegistries} provider was found on the
* classpath
*/
public MonitorRegistry unique() {
//Implementation based on SLF4J's
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
return selectedRegistry;
case NOP_FALLBACK_INITIALIZATION:
case ONGOING_INITIALIZATION:
default:
return MonitorRegistry.NOOP;
}
}
private void performInitialization() {
final Iterator<MonitorRegistry> registries = iterator();
if (!registries.hasNext()) {
throw new IllegalStateException("Could not find any MonitorRegistries 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());
selectedRegistry = registries.next();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
}
if (selectedRegistry != null && registries.hasNext()) {
logger.warn(String.format("Multiple metrics implementations found. " +
"Selected %s, ignoring other implementations", selectedRegistry.getClass().getName()));
}
if (selectedRegistry == null) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
logger.debug("No metrics implementation found on the classpath.");
}
return candidate;
}
/**

View File

@ -35,7 +35,7 @@ public class MonitorRegistriesTest {
registry.getClass());
}
@Test(expected = IllegalStateException.class)
@Test
public final void uniqueShouldThrowIllegalStateExceptionIfMoreThanOneProviderIsRegistered() {
final MonitorRegistries objectUnderTest = MonitorRegistries.instance();

View File

@ -59,6 +59,11 @@
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-metrics-yammer</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -22,6 +22,9 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import io.netty.monitor.CounterMonitor;
import io.netty.monitor.MonitorName;
import io.netty.monitor.MonitorRegistries;
/**
* Abstract base class for {@link EventExecutorGroup} implementations that handles their tasks with multiple threads at
* the same time.
@ -30,6 +33,8 @@ public abstract class MultithreadEventExecutorGroup implements EventExecutorGrou
public static final int DEFAULT_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
private static final AtomicInteger poolId = new AtomicInteger();
private final CounterMonitor threadCounter = MonitorRegistries.instance()
.unique().newCounterMonitor(new MonitorName(getClass(), "total-threads"));
final ChannelTaskScheduler scheduler;
private final EventExecutor[] children;
@ -57,6 +62,7 @@ public abstract class MultithreadEventExecutorGroup implements EventExecutorGrou
if (threadFactory == null) {
threadFactory = new DefaultThreadFactory();
}
threadCounter.increment(nThreads);
scheduler = new ChannelTaskScheduler(threadFactory);

View File

@ -15,6 +15,10 @@
*/
package io.netty.channel;
import io.netty.monitor.CounterMonitor;
import io.netty.monitor.MonitorName;
import io.netty.monitor.MonitorRegistries;
import java.util.concurrent.ThreadFactory;
/**
@ -22,6 +26,8 @@ import java.util.concurrent.ThreadFactory;
*
*/
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
protected CounterMonitor channelCounter = MonitorRegistries.instance()
.unique().newCounterMonitor(new MonitorName(getClass(), "total-channels-registered"));
/**
*
@ -68,6 +74,8 @@ public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor im
}
});
}
channelCounter.increment();
return promise;
}
}

View File

@ -15,6 +15,7 @@
*/
package io.netty.channel.socket.nio;
import io.netty.channel.Channel;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelTaskScheduler;
@ -23,6 +24,9 @@ import io.netty.channel.SingleThreadEventLoop;
import io.netty.channel.socket.nio.AbstractNioChannel.NioUnsafe;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
import io.netty.monitor.CounterMonitor;
import io.netty.monitor.MonitorName;
import io.netty.monitor.MonitorRegistries;
import java.io.IOException;
import java.nio.channels.CancelledKeyException;
@ -38,6 +42,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@ -46,6 +51,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
*/
public final class NioEventLoop extends SingleThreadEventLoop {
private final CounterMonitor selectorWokeUpBeforeTime = MonitorRegistries.instance()
.unique().newCounterMonitor(new MonitorName(getClass(), "Selector.select-early-wake-up"));
/**
* Internal Netty logger.
@ -232,6 +239,14 @@ public final class NioEventLoop extends SingleThreadEventLoop {
try {
long beforeSelect = System.nanoTime();
int selected = SelectorUtil.select(selector);
//measure how long select took & convert nano time to milliseconds
long totalSelectTime = System.nanoTime() - beforeSelect;
long selectTime = TimeUnit.MILLISECONDS.convert(totalSelectTime, TimeUnit.NANOSECONDS);
if (selectTime < SelectorUtil.SELECT_TIMEOUT) {
selectorWokeUpBeforeTime.increment();
}
if (SelectorUtil.EPOLL_BUG_WORKAROUND) {
if (selected == 0) {
long timeBlocked = System.nanoTime() - beforeSelect;