View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.io;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.concurrent.TimeUnit;
25  import java.util.concurrent.atomic.AtomicLong;
26  import java.util.concurrent.atomic.LongAdder;
27  
28  import org.eclipse.jetty.util.annotation.ManagedAttribute;
29  import org.eclipse.jetty.util.annotation.ManagedObject;
30  import org.eclipse.jetty.util.annotation.ManagedOperation;
31  import org.eclipse.jetty.util.component.AbstractLifeCycle;
32  import org.eclipse.jetty.util.component.ContainerLifeCycle;
33  import org.eclipse.jetty.util.component.Dumpable;
34  import org.eclipse.jetty.util.statistic.CounterStatistic;
35  import org.eclipse.jetty.util.statistic.SampleStatistic;
36  
37  /**
38   * <p>A {@link Connection.Listener} that tracks connection statistics.</p>
39   * <p>Adding an instance of this class as a bean to a server Connector
40   * (for the server) or to HttpClient (for the client) will trigger the
41   * tracking of the connection statistics for all connections managed
42   * by the server Connector or by HttpClient.</p>
43   */
44  @ManagedObject("Tracks statistics on connections")
45  public class ConnectionStatistics extends AbstractLifeCycle implements Connection.Listener, Dumpable
46  {
47      private final CounterStatistic _connections = new CounterStatistic();
48      private final SampleStatistic _connectionsDuration = new SampleStatistic();
49      private final LongAdder _rcvdBytes = new LongAdder();
50      private final AtomicLong _bytesInStamp = new AtomicLong();
51      private final LongAdder _sentBytes = new LongAdder();
52      private final AtomicLong _bytesOutStamp = new AtomicLong();
53      private final LongAdder _messagesIn = new LongAdder();
54      private final AtomicLong _messagesInStamp = new AtomicLong();
55      private final LongAdder _messagesOut = new LongAdder();
56      private final AtomicLong _messagesOutStamp = new AtomicLong();
57  
58      @ManagedOperation(value = "Resets the statistics", impact = "ACTION")
59      public void reset()
60      {
61          _connections.reset();
62          _connectionsDuration.reset();
63          _rcvdBytes.reset();
64          _bytesInStamp.set(System.nanoTime());
65          _sentBytes.reset();
66          _bytesOutStamp.set(System.nanoTime());
67          _messagesIn.reset();
68          _messagesInStamp.set(System.nanoTime());
69          _messagesOut.reset();
70          _messagesOutStamp.set(System.nanoTime());
71      }
72  
73      @Override
74      protected void doStart() throws Exception
75      {
76          reset();
77      }
78  
79      @Override
80      public void onOpened(Connection connection)
81      {
82          if (!isStarted())
83              return;
84  
85          _connections.increment();
86      }
87  
88      @Override
89      public void onClosed(Connection connection)
90      {
91          if (!isStarted())
92              return;
93  
94          _connections.decrement();
95  
96          long elapsed = System.currentTimeMillis() - connection.getCreatedTimeStamp();
97          _connectionsDuration.set(elapsed);
98  
99          long bytesIn = connection.getBytesIn();
100         if (bytesIn > 0)
101             _rcvdBytes.add(bytesIn);
102         long bytesOut = connection.getBytesOut();
103         if (bytesOut > 0)
104             _sentBytes.add(bytesOut);
105 
106         long messagesIn = connection.getMessagesIn();
107         if (messagesIn > 0)
108             _messagesIn.add(messagesIn);
109         long messagesOut = connection.getMessagesOut();
110         if (messagesOut > 0)
111             _messagesOut.add(messagesOut);
112     }
113 
114     @ManagedAttribute("Total number of bytes received by tracked connections")
115     public long getReceivedBytes()
116     {
117         return _rcvdBytes.sum();
118     }
119 
120     @ManagedAttribute("Total number of bytes received per second since the last invocation of this method")
121     public long getReceivedBytesRate()
122     {
123         long now = System.nanoTime();
124         long then = _bytesInStamp.getAndSet(now);
125         long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then);
126         return elapsed == 0 ? 0 : getReceivedBytes() * 1000 / elapsed;
127     }
128 
129     @ManagedAttribute("Total number of bytes sent by tracked connections")
130     public long getSentBytes()
131     {
132         return _sentBytes.sum();
133     }
134 
135     @ManagedAttribute("Total number of bytes sent per second since the last invocation of this method")
136     public long getSentBytesRate()
137     {
138         long now = System.nanoTime();
139         long then = _bytesOutStamp.getAndSet(now);
140         long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then);
141         return elapsed == 0 ? 0 : getSentBytes() * 1000 / elapsed;
142     }
143 
144     @ManagedAttribute("The max duration of a connection in ms")
145     public long getConnectionDurationMax()
146     {
147         return _connectionsDuration.getMax();
148     }
149 
150     @ManagedAttribute("The mean duration of a connection in ms")
151     public double getConnectionDurationMean()
152     {
153         return _connectionsDuration.getMean();
154     }
155 
156     @ManagedAttribute("The standard deviation of the duration of a connection")
157     public double getConnectionDurationStdDev()
158     {
159         return _connectionsDuration.getStdDev();
160     }
161 
162     @ManagedAttribute("The total number of connections opened")
163     public long getConnectionsTotal()
164     {
165         return _connections.getTotal();
166     }
167 
168     @ManagedAttribute("The current number of open connections")
169     public long getConnections()
170     {
171         return _connections.getCurrent();
172     }
173 
174     @ManagedAttribute("The max number of open connections")
175     public long getConnectionsMax()
176     {
177         return _connections.getMax();
178     }
179 
180     @ManagedAttribute("The total number of messages received")
181     public long getReceivedMessages()
182     {
183         return _messagesIn.sum();
184     }
185 
186     @ManagedAttribute("Total number of messages received per second since the last invocation of this method")
187     public long getReceivedMessagesRate()
188     {
189         long now = System.nanoTime();
190         long then = _messagesInStamp.getAndSet(now);
191         long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then);
192         return elapsed == 0 ? 0 : getReceivedMessages() * 1000 / elapsed;
193     }
194 
195     @ManagedAttribute("The total number of messages sent")
196     public long getSentMessages()
197     {
198         return _messagesOut.sum();
199     }
200 
201     @ManagedAttribute("Total number of messages sent per second since the last invocation of this method")
202     public long getSentMessagesRate()
203     {
204         long now = System.nanoTime();
205         long then = _messagesOutStamp.getAndSet(now);
206         long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then);
207         return elapsed == 0 ? 0 : getSentMessages() * 1000 / elapsed;
208     }
209 
210     @Override
211     public String dump()
212     {
213         return ContainerLifeCycle.dump(this);
214     }
215 
216     @Override
217     public void dump(Appendable out, String indent) throws IOException
218     {
219         ContainerLifeCycle.dumpObject(out, this);
220         List<String> children = new ArrayList<>();
221         children.add(String.format("connections=%s", _connections));
222         children.add(String.format("durations=%s", _connectionsDuration));
223         children.add(String.format("bytes in/out=%s/%s", getReceivedBytes(), getSentBytes()));
224         children.add(String.format("messages in/out=%s/%s", getReceivedMessages(), getSentMessages()));
225         ContainerLifeCycle.dump(out, indent, children);
226     }
227 
228     @Override
229     public String toString()
230     {
231         return String.format("%s@%x", getClass().getSimpleName(), hashCode());
232     }
233 }