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.server;
20  
21  import java.io.IOException;
22  import java.util.Arrays;
23  import java.util.Map;
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;
29  
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;
40  
41  
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.
46   */
47  @ManagedObject("Connector Statistics")
48  public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable, Connection.Listener
49  {
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;
62  
63      @Override
64      public void onOpened(Connection connection)
65      {
66          if (isStarted())
67          {
68              _connectionStats.increment();
69              _samples.put(connection,ZERO);
70          }
71      }
72  
73      @Override
74      public void onClosed(Connection connection)
75      {
76          if (isStarted())
77          {
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());
84  
85              Sample sample=_samples.remove(connection);
86              if (sample!=null)
87              {
88                  _closedIn.addAndGet(msgsIn-sample._messagesIn);
89                  _closedOut.addAndGet(msgsOut-sample._messagesOut);
90              }
91          }
92      }
93  
94      @ManagedAttribute("Total number of bytes received by this connector")
95      public int getBytesIn()
96      {
97          // TODO
98          return -1;
99      }
100 
101     @ManagedAttribute("Total number of bytes sent by this connector")
102     public int getBytesOut()
103     {
104         // TODO
105         return -1;
106     }
107 
108     @ManagedAttribute("Total number of connections seen by this connector")
109     public int getConnections()
110     {
111         return (int)_connectionStats.getTotal();
112     }
113 
114     @ManagedAttribute("Connection duration maximum in ms")
115     public long getConnectionDurationMax()
116     {
117         return _connectionDurationStats.getMax();
118     }
119 
120     @ManagedAttribute("Connection duration mean in ms")
121     public double getConnectionDurationMean()
122     {
123         return _connectionDurationStats.getMean();
124     }
125 
126     @ManagedAttribute("Connection duration standard deviation")
127     public double getConnectionDurationStdDev()
128     {
129         return _connectionDurationStats.getStdDev();
130     }
131 
132     @ManagedAttribute("Messages In for all connections")
133     public int getMessagesIn()
134     {
135         return (int)_messagesIn.getTotal();
136     }
137 
138     @ManagedAttribute("Messages In per connection maximum")
139     public int getMessagesInPerConnectionMax()
140     {
141         return (int)_messagesIn.getMax();
142     }
143 
144     @ManagedAttribute("Messages In per connection mean")
145     public double getMessagesInPerConnectionMean()
146     {
147         return _messagesIn.getMean();
148     }
149 
150     @ManagedAttribute("Messages In per connection standard deviation")
151     public double getMessagesInPerConnectionStdDev()
152     {
153         return _messagesIn.getStdDev();
154     }
155 
156     @ManagedAttribute("Connections open")
157     public int getConnectionsOpen()
158     {
159         return (int)_connectionStats.getCurrent();
160     }
161 
162     @ManagedAttribute("Connections open maximum")
163     public int getConnectionsOpenMax()
164     {
165         return (int)_connectionStats.getMax();
166     }
167 
168     @ManagedAttribute("Messages Out for all connections")
169     public int getMessagesOut()
170     {
171         return (int)_messagesIn.getTotal();
172     }
173 
174     @ManagedAttribute("Messages In per connection maximum")
175     public int getMessagesOutPerConnectionMax()
176     {
177         return (int)_messagesIn.getMax();
178     }
179 
180     @ManagedAttribute("Messages In per connection mean")
181     public double getMessagesOutPerConnectionMean()
182     {
183         return _messagesIn.getMean();
184     }
185 
186     @ManagedAttribute("Messages In per connection standard deviation")
187     public double getMessagesOutPerConnectionStdDev()
188     {
189         return _messagesIn.getStdDev();
190     }
191 
192     @ManagedAttribute("Connection statistics started ms since epoch")
193     public long getStartedMillis()
194     {
195         long start = _startMillis.get();
196         return start < 0 ? 0 : System.currentTimeMillis() - start;
197     }
198 
199     @ManagedAttribute("Messages in per second calculated over period since last called")
200     public int getMessagesInPerSecond()
201     {
202         update();
203         return _messagesInPerSecond;
204     }
205 
206     @ManagedAttribute("Messages out per second calculated over period since last called")
207     public int getMessagesOutPerSecond()
208     {
209         update();
210         return _messagesOutPerSecond;
211     }
212 
213     @Override
214     public void doStart()
215     {
216         reset();
217     }
218 
219     @Override
220     public void doStop()
221     {
222         _samples.clear();
223     }
224 
225     @ManagedOperation("Reset the statistics")
226     public void reset()
227     {
228         _startMillis.set(System.currentTimeMillis());
229         _messagesIn.reset();
230         _messagesOut.reset();
231         _connectionStats.reset();
232         _connectionDurationStats.reset();
233         _samples.clear();
234     }
235 
236     @Override
237     @ManagedOperation("dump thread state")
238     public String dump()
239     {
240         return ContainerLifeCycle.dump(this);
241     }
242 
243     @Override
244     public void dump(Appendable out, String indent) throws IOException
245     {
246         ContainerLifeCycle.dumpObject(out,this);
247         ContainerLifeCycle.dump(out,indent,Arrays.asList(new String[]{"connections="+_connectionStats,"duration="+_connectionDurationStats,"in="+_messagesIn,"out="+_messagesOut}));
248     }
249     
250     public static void addToAllConnectors(Server server)
251     {
252         for (Connector connector : server.getConnectors())
253         {
254             if (connector instanceof Container)
255              ((Container)connector).addBean(new ConnectorStatistics());
256         }
257     }  
258     
259     private static final long SECOND_NANOS=TimeUnit.SECONDS.toNanos(1);
260     private synchronized void update()
261     {
262         long now=System.nanoTime();
263         long then=_nanoStamp.get();
264         long duration=now-then;
265                 
266         if (duration>SECOND_NANOS/2)
267         {
268             if (_nanoStamp.compareAndSet(then,now))
269             {
270                 long msgsIn=_closedIn.getAndSet(0);
271                 long msgsOut=_closedOut.getAndSet(0);
272 
273                 for (Map.Entry<Connection, Sample> entry : _samples.entrySet())
274                 {
275                     Connection connection=entry.getKey();
276                     Sample sample = entry.getValue();
277                     Sample next = new Sample(connection);
278                     if (_samples.replace(connection,sample,next))
279                     {
280                         msgsIn+=next._messagesIn-sample._messagesIn;
281                         msgsOut+=next._messagesOut-sample._messagesOut;
282                     }
283                 }
284                 
285                 _messagesInPerSecond=(int)(msgsIn*SECOND_NANOS/duration);
286                 _messagesOutPerSecond=(int)(msgsOut*SECOND_NANOS/duration);
287             }
288         }
289     }
290     
291     private static class Sample
292     {
293         Sample()
294         {
295             _messagesIn=0;
296             _messagesOut=0;
297         }
298         
299         Sample(Connection connection)
300         {
301             _messagesIn=connection.getMessagesIn();
302             _messagesOut=connection.getMessagesOut();
303         }
304         
305         final int _messagesIn;
306         final int _messagesOut;
307     }
308 }