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:
parent
bd093c4ab0
commit
3a52cc410a
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,7 @@ public class MonitorRegistriesTest {
|
||||
registry.getClass());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@Test
|
||||
public final void uniqueShouldThrowIllegalStateExceptionIfMoreThanOneProviderIsRegistered() {
|
||||
final MonitorRegistries objectUnderTest = MonitorRegistries.instance();
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user