2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.server;
21 import java.io.IOException;
22 import java.util.Arrays;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.atomic.AtomicInteger;
28 import java.util.concurrent.atomic.AtomicLong;
30 import org.eclipse.jetty.io.Connection;
31 import org.eclipse.jetty.util.annotation.ManagedAttribute;
32 import org.eclipse.jetty.util.annotation.ManagedObject;
33 import org.eclipse.jetty.util.annotation.ManagedOperation;
34 import org.eclipse.jetty.util.component.AbstractLifeCycle;
35 import org.eclipse.jetty.util.component.Container;
36 import org.eclipse.jetty.util.component.ContainerLifeCycle;
37 import org.eclipse.jetty.util.component.Dumpable;
38 import org.eclipse.jetty.util.statistic.CounterStatistic;
39 import org.eclipse.jetty.util.statistic.SampleStatistic;
42 /* ------------------------------------------------------------ */
43 /** A Connector.Listener that gathers Connector and Connections Statistics.
44 * Adding an instance of this class as with {@link AbstractConnector#addBean(Object)}
45 * will register the listener with all connections accepted by that connector.
47 @ManagedObject("Connector Statistics")
48 public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable, Connection.Listener
50 private final static Sample ZERO=new Sample();
51 private final AtomicLong _startMillis = new AtomicLong(-1L);
52 private final CounterStatistic _connectionStats = new CounterStatistic();
53 private final SampleStatistic _messagesIn = new SampleStatistic();
54 private final SampleStatistic _messagesOut = new SampleStatistic();
55 private final SampleStatistic _connectionDurationStats = new SampleStatistic();
56 private final ConcurrentMap<Connection, Sample> _samples = new ConcurrentHashMap<>();
57 private final AtomicInteger _closedIn = new AtomicInteger();
58 private final AtomicInteger _closedOut = new AtomicInteger();
59 private AtomicLong _nanoStamp=new AtomicLong();
60 private volatile int _messagesInPerSecond;
61 private volatile int _messagesOutPerSecond;
64 public void onOpened(Connection connection)
68 _connectionStats.increment();
69 _samples.put(connection,ZERO);
74 public void onClosed(Connection connection)
78 int msgsIn=connection.getMessagesIn();
79 int msgsOut=connection.getMessagesOut();
80 _messagesIn.set(msgsIn);
81 _messagesOut.set(msgsOut);
82 _connectionStats.decrement();
83 _connectionDurationStats.set(System.currentTimeMillis()-connection.getCreatedTimeStamp());
85 Sample sample=_samples.remove(connection);
88 _closedIn.addAndGet(msgsIn-sample._messagesIn);
89 _closedOut.addAndGet(msgsOut-sample._messagesOut);
94 @ManagedAttribute("Total number of bytes received by this connector")
95 public int getBytesIn()
101 @ManagedAttribute("Total number of bytes sent by this connector")
102 public int getBytesOut()
108 @ManagedAttribute("Total number of connections seen by this connector")
109 public int getConnections()
111 return (int)_connectionStats.getTotal();
114 @ManagedAttribute("Connection duration maximum in ms")
115 public long getConnectionDurationMax()
117 return _connectionDurationStats.getMax();
120 @ManagedAttribute("Connection duration mean in ms")
121 public double getConnectionDurationMean()
123 return _connectionDurationStats.getMean();
126 @ManagedAttribute("Connection duration standard deviation")
127 public double getConnectionDurationStdDev()
129 return _connectionDurationStats.getStdDev();
132 @ManagedAttribute("Messages In for all connections")
133 public int getMessagesIn()
135 return (int)_messagesIn.getTotal();
138 @ManagedAttribute("Messages In per connection maximum")
139 public int getMessagesInPerConnectionMax()
141 return (int)_messagesIn.getMax();
144 @ManagedAttribute("Messages In per connection mean")
145 public double getMessagesInPerConnectionMean()
147 return _messagesIn.getMean();
150 @ManagedAttribute("Messages In per connection standard deviation")
151 public double getMessagesInPerConnectionStdDev()
153 return _messagesIn.getStdDev();
156 @ManagedAttribute("Connections open")
157 public int getConnectionsOpen()
159 return (int)_connectionStats.getCurrent();
162 @ManagedAttribute("Connections open maximum")
163 public int getConnectionsOpenMax()
165 return (int)_connectionStats.getMax();
168 @ManagedAttribute("Messages Out for all connections")
169 public int getMessagesOut()
171 return (int)_messagesIn.getTotal();
174 @ManagedAttribute("Messages In per connection maximum")
175 public int getMessagesOutPerConnectionMax()
177 return (int)_messagesIn.getMax();
180 @ManagedAttribute("Messages In per connection mean")
181 public double getMessagesOutPerConnectionMean()
183 return _messagesIn.getMean();
186 @ManagedAttribute("Messages In per connection standard deviation")
187 public double getMessagesOutPerConnectionStdDev()
189 return _messagesIn.getStdDev();
192 @ManagedAttribute("Connection statistics started ms since epoch")
193 public long getStartedMillis()
195 long start = _startMillis.get();
196 return start < 0 ? 0 : System.currentTimeMillis() - start;
199 @ManagedAttribute("Messages in per second calculated over period since last called")
200 public int getMessagesInPerSecond()
203 return _messagesInPerSecond;
206 @ManagedAttribute("Messages out per second calculated over period since last called")
207 public int getMessagesOutPerSecond()
210 return _messagesOutPerSecond;
214 public void doStart()
225 @ManagedOperation("Reset the statistics")
228 _startMillis.set(System.currentTimeMillis());
230 _messagesOut.reset();
231 _connectionStats.reset();
232 _connectionDurationStats.reset();
237 @ManagedOperation("dump thread state")
240 return ContainerLifeCycle.dump(this);
244 public void dump(Appendable out, String indent) throws IOException
246 ContainerLifeCycle.dumpObject(out,this);
247 ContainerLifeCycle.dump(out,indent,Arrays.asList(new String[]{"connections="+_connectionStats,"duration="+_connectionDurationStats,"in="+_messagesIn,"out="+_messagesOut}));
250 public static void addToAllConnectors(Server server)
252 for (Connector connector : server.getConnectors())
254 if (connector instanceof Container)
255 ((Container)connector).addBean(new ConnectorStatistics());
259 private static final long SECOND_NANOS=TimeUnit.SECONDS.toNanos(1);
260 private synchronized void update()
262 long now=System.nanoTime();
263 long then=_nanoStamp.get();
264 long duration=now-then;
266 if (duration>SECOND_NANOS/2)
268 if (_nanoStamp.compareAndSet(then,now))
270 long msgsIn=_closedIn.getAndSet(0);
271 long msgsOut=_closedOut.getAndSet(0);
273 for (Map.Entry<Connection, Sample> entry : _samples.entrySet())
275 Connection connection=entry.getKey();
276 Sample sample = entry.getValue();
277 Sample next = new Sample(connection);
278 if (_samples.replace(connection,sample,next))
280 msgsIn+=next._messagesIn-sample._messagesIn;
281 msgsOut+=next._messagesOut-sample._messagesOut;
285 _messagesInPerSecond=(int)(msgsIn*SECOND_NANOS/duration);
286 _messagesOutPerSecond=(int)(msgsOut*SECOND_NANOS/duration);
291 private static class Sample
299 Sample(Connection connection)
301 _messagesIn=connection.getMessagesIn();
302 _messagesOut=connection.getMessagesOut();
305 final int _messagesIn;
306 final int _messagesOut;