| // |
| // ======================================================================== |
| // 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.server; |
| |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicLong; |
| import java.util.concurrent.atomic.LongAdder; |
| |
| import org.eclipse.jetty.io.Connection; |
| 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.Container; |
| 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; |
| |
| |
| /* ------------------------------------------------------------ */ |
| /** A Connector.Listener that gathers Connector and Connections Statistics. |
| * Adding an instance of this class as with {@link AbstractConnector#addBean(Object)} |
| * will register the listener with all connections accepted by that connector. |
| * |
| * @deprecated use {@link ServerConnectionStatistics} instead. |
| */ |
| @Deprecated |
| @ManagedObject("Connector Statistics") |
| public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable, Connection.Listener |
| { |
| private final static Sample ZERO=new Sample(); |
| private final AtomicLong _startMillis = new AtomicLong(-1L); |
| private final CounterStatistic _connectionStats = new CounterStatistic(); |
| private final SampleStatistic _messagesIn = new SampleStatistic(); |
| private final SampleStatistic _messagesOut = new SampleStatistic(); |
| private final SampleStatistic _connectionDurationStats = new SampleStatistic(); |
| private final ConcurrentMap<Connection, Sample> _samples = new ConcurrentHashMap<>(); |
| private final LongAdder _closedIn = new LongAdder(); |
| private final LongAdder _closedOut = new LongAdder(); |
| private AtomicLong _nanoStamp=new AtomicLong(); |
| private volatile int _messagesInPerSecond; |
| private volatile int _messagesOutPerSecond; |
| |
| @Override |
| public void onOpened(Connection connection) |
| { |
| if (isStarted()) |
| { |
| _connectionStats.increment(); |
| _samples.put(connection,ZERO); |
| } |
| } |
| |
| @Override |
| public void onClosed(Connection connection) |
| { |
| if (isStarted()) |
| { |
| int msgsIn=connection.getMessagesIn(); |
| int msgsOut=connection.getMessagesOut(); |
| _messagesIn.set(msgsIn); |
| _messagesOut.set(msgsOut); |
| _connectionStats.decrement(); |
| _connectionDurationStats.set(System.currentTimeMillis()-connection.getCreatedTimeStamp()); |
| |
| Sample sample=_samples.remove(connection); |
| if (sample!=null) |
| { |
| _closedIn.add(msgsIn-sample._messagesIn); |
| _closedOut.add(msgsOut-sample._messagesOut); |
| } |
| } |
| } |
| |
| @ManagedAttribute("Total number of bytes received by this connector") |
| public int getBytesIn() |
| { |
| // TODO |
| return -1; |
| } |
| |
| @ManagedAttribute("Total number of bytes sent by this connector") |
| public int getBytesOut() |
| { |
| // TODO |
| return -1; |
| } |
| |
| @ManagedAttribute("Total number of connections seen by this connector") |
| public int getConnections() |
| { |
| return (int)_connectionStats.getTotal(); |
| } |
| |
| @ManagedAttribute("Connection duration maximum in ms") |
| public long getConnectionDurationMax() |
| { |
| return _connectionDurationStats.getMax(); |
| } |
| |
| @ManagedAttribute("Connection duration mean in ms") |
| public double getConnectionDurationMean() |
| { |
| return _connectionDurationStats.getMean(); |
| } |
| |
| @ManagedAttribute("Connection duration standard deviation") |
| public double getConnectionDurationStdDev() |
| { |
| return _connectionDurationStats.getStdDev(); |
| } |
| |
| @ManagedAttribute("Messages In for all connections") |
| public int getMessagesIn() |
| { |
| return (int)_messagesIn.getTotal(); |
| } |
| |
| @ManagedAttribute("Messages In per connection maximum") |
| public int getMessagesInPerConnectionMax() |
| { |
| return (int)_messagesIn.getMax(); |
| } |
| |
| @ManagedAttribute("Messages In per connection mean") |
| public double getMessagesInPerConnectionMean() |
| { |
| return _messagesIn.getMean(); |
| } |
| |
| @ManagedAttribute("Messages In per connection standard deviation") |
| public double getMessagesInPerConnectionStdDev() |
| { |
| return _messagesIn.getStdDev(); |
| } |
| |
| @ManagedAttribute("Connections open") |
| public int getConnectionsOpen() |
| { |
| return (int)_connectionStats.getCurrent(); |
| } |
| |
| @ManagedAttribute("Connections open maximum") |
| public int getConnectionsOpenMax() |
| { |
| return (int)_connectionStats.getMax(); |
| } |
| |
| @ManagedAttribute("Messages Out for all connections") |
| public int getMessagesOut() |
| { |
| return (int)_messagesIn.getTotal(); |
| } |
| |
| @ManagedAttribute("Messages In per connection maximum") |
| public int getMessagesOutPerConnectionMax() |
| { |
| return (int)_messagesIn.getMax(); |
| } |
| |
| @ManagedAttribute("Messages In per connection mean") |
| public double getMessagesOutPerConnectionMean() |
| { |
| return _messagesIn.getMean(); |
| } |
| |
| @ManagedAttribute("Messages In per connection standard deviation") |
| public double getMessagesOutPerConnectionStdDev() |
| { |
| return _messagesIn.getStdDev(); |
| } |
| |
| @ManagedAttribute("Connection statistics started ms since epoch") |
| public long getStartedMillis() |
| { |
| long start = _startMillis.get(); |
| return start < 0 ? 0 : System.currentTimeMillis() - start; |
| } |
| |
| @ManagedAttribute("Messages in per second calculated over period since last called") |
| public int getMessagesInPerSecond() |
| { |
| update(); |
| return _messagesInPerSecond; |
| } |
| |
| @ManagedAttribute("Messages out per second calculated over period since last called") |
| public int getMessagesOutPerSecond() |
| { |
| update(); |
| return _messagesOutPerSecond; |
| } |
| |
| @Override |
| public void doStart() |
| { |
| reset(); |
| } |
| |
| @Override |
| public void doStop() |
| { |
| _samples.clear(); |
| } |
| |
| @ManagedOperation("Reset the statistics") |
| public void reset() |
| { |
| _startMillis.set(System.currentTimeMillis()); |
| _messagesIn.reset(); |
| _messagesOut.reset(); |
| _connectionStats.reset(); |
| _connectionDurationStats.reset(); |
| _samples.clear(); |
| } |
| |
| @Override |
| @ManagedOperation("dump thread state") |
| public String dump() |
| { |
| return ContainerLifeCycle.dump(this); |
| } |
| |
| @Override |
| public void dump(Appendable out, String indent) throws IOException |
| { |
| ContainerLifeCycle.dumpObject(out,this); |
| ContainerLifeCycle.dump(out,indent,Arrays.asList(new String[]{"connections="+_connectionStats,"duration="+_connectionDurationStats,"in="+_messagesIn,"out="+_messagesOut})); |
| } |
| |
| public static void addToAllConnectors(Server server) |
| { |
| for (Connector connector : server.getConnectors()) |
| { |
| if (connector instanceof Container) |
| ((Container)connector).addBean(new ConnectorStatistics()); |
| } |
| } |
| |
| private static final long SECOND_NANOS=TimeUnit.SECONDS.toNanos(1); |
| private synchronized void update() |
| { |
| long now=System.nanoTime(); |
| long then=_nanoStamp.get(); |
| long duration=now-then; |
| |
| if (duration>SECOND_NANOS/2) |
| { |
| if (_nanoStamp.compareAndSet(then,now)) |
| { |
| long msgsIn=_closedIn.sumThenReset(); |
| long msgsOut=_closedOut.sumThenReset(); |
| |
| for (Map.Entry<Connection, Sample> entry : _samples.entrySet()) |
| { |
| Connection connection=entry.getKey(); |
| Sample sample = entry.getValue(); |
| Sample next = new Sample(connection); |
| if (_samples.replace(connection,sample,next)) |
| { |
| msgsIn+=next._messagesIn-sample._messagesIn; |
| msgsOut+=next._messagesOut-sample._messagesOut; |
| } |
| } |
| |
| _messagesInPerSecond=(int)(msgsIn*SECOND_NANOS/duration); |
| _messagesOutPerSecond=(int)(msgsOut*SECOND_NANOS/duration); |
| } |
| } |
| } |
| |
| private static class Sample |
| { |
| Sample() |
| { |
| _messagesIn=0; |
| _messagesOut=0; |
| } |
| |
| Sample(Connection connection) |
| { |
| _messagesIn=connection.getMessagesIn(); |
| _messagesOut=connection.getMessagesOut(); |
| } |
| |
| final int _messagesIn; |
| final int _messagesOut; |
| } |
| } |