1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
44
45
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
98 return -1;
99 }
100
101 @ManagedAttribute("Total number of bytes sent by this connector")
102 public int getBytesOut()
103 {
104
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 }