| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.io; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicLong; |
| import java.util.concurrent.atomic.LongAdder; |
| |
| import org.eclipse.jetty.util.annotation.ManagedAttribute; |
| import org.eclipse.jetty.util.annotation.ManagedObject; |
| import org.eclipse.jetty.util.annotation.ManagedOperation; |
| import org.eclipse.jetty.util.component.AbstractLifeCycle; |
| import org.eclipse.jetty.util.component.ContainerLifeCycle; |
| import org.eclipse.jetty.util.component.Dumpable; |
| import org.eclipse.jetty.util.statistic.CounterStatistic; |
| import org.eclipse.jetty.util.statistic.SampleStatistic; |
| |
| /** |
| * <p>A {@link Connection.Listener} that tracks connection statistics.</p> |
| * <p>Adding an instance of this class as a bean to a server Connector |
| * (for the server) or to HttpClient (for the client) will trigger the |
| * tracking of the connection statistics for all connections managed |
| * by the server Connector or by HttpClient.</p> |
| */ |
| @ManagedObject("Tracks statistics on connections") |
| public class ConnectionStatistics extends AbstractLifeCycle implements Connection.Listener, Dumpable |
| { |
| private final CounterStatistic _connections = new CounterStatistic(); |
| private final SampleStatistic _connectionsDuration = new SampleStatistic(); |
| private final LongAdder _rcvdBytes = new LongAdder(); |
| private final AtomicLong _bytesInStamp = new AtomicLong(); |
| private final LongAdder _sentBytes = new LongAdder(); |
| private final AtomicLong _bytesOutStamp = new AtomicLong(); |
| private final LongAdder _messagesIn = new LongAdder(); |
| private final AtomicLong _messagesInStamp = new AtomicLong(); |
| private final LongAdder _messagesOut = new LongAdder(); |
| private final AtomicLong _messagesOutStamp = new AtomicLong(); |
| |
| @ManagedOperation(value = "Resets the statistics", impact = "ACTION") |
| public void reset() |
| { |
| _connections.reset(); |
| _connectionsDuration.reset(); |
| _rcvdBytes.reset(); |
| _bytesInStamp.set(System.nanoTime()); |
| _sentBytes.reset(); |
| _bytesOutStamp.set(System.nanoTime()); |
| _messagesIn.reset(); |
| _messagesInStamp.set(System.nanoTime()); |
| _messagesOut.reset(); |
| _messagesOutStamp.set(System.nanoTime()); |
| } |
| |
| @Override |
| protected void doStart() throws Exception |
| { |
| reset(); |
| } |
| |
| @Override |
| public void onOpened(Connection connection) |
| { |
| if (!isStarted()) |
| return; |
| |
| _connections.increment(); |
| } |
| |
| @Override |
| public void onClosed(Connection connection) |
| { |
| if (!isStarted()) |
| return; |
| |
| _connections.decrement(); |
| |
| long elapsed = System.currentTimeMillis() - connection.getCreatedTimeStamp(); |
| _connectionsDuration.set(elapsed); |
| |
| long bytesIn = connection.getBytesIn(); |
| if (bytesIn > 0) |
| _rcvdBytes.add(bytesIn); |
| long bytesOut = connection.getBytesOut(); |
| if (bytesOut > 0) |
| _sentBytes.add(bytesOut); |
| |
| long messagesIn = connection.getMessagesIn(); |
| if (messagesIn > 0) |
| _messagesIn.add(messagesIn); |
| long messagesOut = connection.getMessagesOut(); |
| if (messagesOut > 0) |
| _messagesOut.add(messagesOut); |
| } |
| |
| @ManagedAttribute("Total number of bytes received by tracked connections") |
| public long getReceivedBytes() |
| { |
| return _rcvdBytes.sum(); |
| } |
| |
| @ManagedAttribute("Total number of bytes received per second since the last invocation of this method") |
| public long getReceivedBytesRate() |
| { |
| long now = System.nanoTime(); |
| long then = _bytesInStamp.getAndSet(now); |
| long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then); |
| return elapsed == 0 ? 0 : getReceivedBytes() * 1000 / elapsed; |
| } |
| |
| @ManagedAttribute("Total number of bytes sent by tracked connections") |
| public long getSentBytes() |
| { |
| return _sentBytes.sum(); |
| } |
| |
| @ManagedAttribute("Total number of bytes sent per second since the last invocation of this method") |
| public long getSentBytesRate() |
| { |
| long now = System.nanoTime(); |
| long then = _bytesOutStamp.getAndSet(now); |
| long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then); |
| return elapsed == 0 ? 0 : getSentBytes() * 1000 / elapsed; |
| } |
| |
| @ManagedAttribute("The max duration of a connection in ms") |
| public long getConnectionDurationMax() |
| { |
| return _connectionsDuration.getMax(); |
| } |
| |
| @ManagedAttribute("The mean duration of a connection in ms") |
| public double getConnectionDurationMean() |
| { |
| return _connectionsDuration.getMean(); |
| } |
| |
| @ManagedAttribute("The standard deviation of the duration of a connection") |
| public double getConnectionDurationStdDev() |
| { |
| return _connectionsDuration.getStdDev(); |
| } |
| |
| @ManagedAttribute("The total number of connections opened") |
| public long getConnectionsTotal() |
| { |
| return _connections.getTotal(); |
| } |
| |
| @ManagedAttribute("The current number of open connections") |
| public long getConnections() |
| { |
| return _connections.getCurrent(); |
| } |
| |
| @ManagedAttribute("The max number of open connections") |
| public long getConnectionsMax() |
| { |
| return _connections.getMax(); |
| } |
| |
| @ManagedAttribute("The total number of messages received") |
| public long getReceivedMessages() |
| { |
| return _messagesIn.sum(); |
| } |
| |
| @ManagedAttribute("Total number of messages received per second since the last invocation of this method") |
| public long getReceivedMessagesRate() |
| { |
| long now = System.nanoTime(); |
| long then = _messagesInStamp.getAndSet(now); |
| long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then); |
| return elapsed == 0 ? 0 : getReceivedMessages() * 1000 / elapsed; |
| } |
| |
| @ManagedAttribute("The total number of messages sent") |
| public long getSentMessages() |
| { |
| return _messagesOut.sum(); |
| } |
| |
| @ManagedAttribute("Total number of messages sent per second since the last invocation of this method") |
| public long getSentMessagesRate() |
| { |
| long now = System.nanoTime(); |
| long then = _messagesOutStamp.getAndSet(now); |
| long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then); |
| return elapsed == 0 ? 0 : getSentMessages() * 1000 / elapsed; |
| } |
| |
| @Override |
| public String dump() |
| { |
| return ContainerLifeCycle.dump(this); |
| } |
| |
| @Override |
| public void dump(Appendable out, String indent) throws IOException |
| { |
| ContainerLifeCycle.dumpObject(out, this); |
| List<String> children = new ArrayList<>(); |
| children.add(String.format("connections=%s", _connections)); |
| children.add(String.format("durations=%s", _connectionsDuration)); |
| children.add(String.format("bytes in/out=%s/%s", getReceivedBytes(), getSentBytes())); |
| children.add(String.format("messages in/out=%s/%s", getReceivedMessages(), getSentMessages())); |
| ContainerLifeCycle.dump(out, indent, children); |
| } |
| |
| @Override |
| public String toString() |
| { |
| return String.format("%s@%x", getClass().getSimpleName(), hashCode()); |
| } |
| } |