1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.monitoring;
19
20 import java.util.Collection;
21
22
23 /**
24 * A <code>Monitor</code> is an abstraction of some application resource that
25 * is instrumented with a set of indicators (Gauges or Counters).
26 * <p>
27 * A Monitor is identified by its Key, that MUST be unique in the application.
28 * To ensure this, the Key class defines the monitor identifier as a combination
29 * of name, subsystem and category.
30 * <p>
31 * The <tt>name</tt> is the human-readable representation of the "resource"
32 * beeing monitored. A typical use is the fully qualified class name + method
33 * signature, or the HTTP request path.
34 * <p>
35 * The <tt>category</tt> is a grouping attribute to reflect the application
36 * layering. Typically for JEE application, you will set category to the N-tier
37 * layer beeing monitored ("servlet", "service", "persistence").
38 * <p>
39 * The <tt>subsystem</tt> is a logical grouping, by use-cases. "account", and
40 * "user" can be used as subsystem for the application account and user
41 * management dedicated components.
42 * <p>
43 * You are free to use more complex Key types, by simple subclassing the Key
44 * class and providing the adequate equals()/hasCode() methods.
45 * <p>
46 * The Counters / Gauges used to store monitored application state are retrieved
47 * based on a "role" String. The monitor can handle as many values as needed,
48 * until any of them has a dedicated role. This allows to easily extend the
49 * monitor by registering custom values.
50 *
51 * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
52 */
53 public interface Monitor
54 {
55 /** default role key for code performances */
56 Role<Counter> PERFORMANCES = new Role<Counter>( "performances", Unit.NANOS, Counter.class );
57
58 /** default role for multi-thread concurrency */
59 Role<Gauge> CONCURRENCY = new Role<Gauge>( "concurrency", Unit.UNARY, Gauge.class );
60
61 /** default Role for the invocation failure counter */
62 Role<Counter> FAILURES = new Role<Counter>( "failures", Unit.UNARY, Counter.class );
63
64 /**
65 * @return the monitor key
66 */
67 Key getKey();
68
69 /**
70 * Retrieve a Counter
71 *
72 * @param role a unique identifier for a Counter in the monitor
73 * @param unit the data unit to count
74 * @return the Counter
75 */
76 Counter getCounter( String role );
77
78 /**
79 * Retrieve or create a Counter in the monitor
80 *
81 * @param role the Counter role in the monitor
82 * @return the Counter
83 */
84 Counter getCounter( Role<Counter> role );
85
86 /**
87 * Retrieve a Gauge in the monitor
88 *
89 * @param role a unique identifier for a Gauge in the monitor
90 * @return the Gauge
91 */
92 Gauge getGauge( String role );
93
94 /**
95 * Retrieve or create a Gauge in the monitor
96 *
97 * @param role the gauge role in the monitor
98 * @return the Gauge
99 */
100 Gauge getGauge( Role<Gauge> role );
101
102 /**
103 * Retrieve a StatValue.
104 *
105 * @param role a unique identifier for a StatValue in the monitor
106 * @return the StatValue
107 */
108 StatValue getValue( String role );
109
110 /**
111 * Retrieve a StatValue in the monitor
112 *
113 * @param role the StatValue role in the monitor
114 * @return the StatValue
115 */
116 <T extends StatValue> T getValue( Role<T> role );
117
118 /**
119 *
120 * @return an unmodifiable collection of registered statValues roles
121 */
122 @SuppressWarnings("unchecked")
123 Collection<Role> getRoles();
124
125 /**
126 *
127 * @return an unmodifiable collection of registered statValues
128 */
129 Collection<StatValue> getValues();
130
131 /**
132 * Reset all StatValues (don't remove them)
133 */
134 void reset();
135
136 /**
137 * Identifier class for Monitors
138 */
139 public static class Key
140 {
141 public final static String DEFAULT = "default";
142
143 private final String name;
144
145 private final String category;
146
147 private final String subsystem;
148
149 public Key( String name, String category, String subsystem )
150 {
151 super();
152 if (name == null)
153 {
154 throw new IllegalArgumentException( "A name must be provided" );
155 }
156 this.name = name;
157 this.category = category != null ? category : DEFAULT;
158 this.subsystem = subsystem != null ? subsystem : DEFAULT;;
159 }
160
161 @Override
162 public String toString()
163 {
164 StringBuffer stb = new StringBuffer();
165 stb.append( "name=" );
166 stb.append( name );
167 if ( category != null )
168 {
169 stb.append( "\ncategory=" );
170 stb.append( category );
171 }
172 if ( subsystem != null )
173 {
174 stb.append( "\nsubsystem=" );
175 stb.append( subsystem );
176 }
177 return stb.toString();
178 }
179
180 @Override
181 public int hashCode()
182 {
183 final int prime = 31;
184 int result = 1;
185 result = prime * result + ( ( category == null ) ? 0 : category.hashCode() );
186 result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
187 result = prime * result + ( ( subsystem == null ) ? 0 : subsystem.hashCode() );
188 return result;
189 }
190
191 @Override
192 public boolean equals( Object obj )
193 {
194 if ( this == obj )
195 {
196 return true;
197 }
198 if ( obj == null )
199 {
200 return false;
201 }
202 if ( getClass() != obj.getClass() )
203 {
204 return false;
205 }
206 final Key other = (Key) obj;
207 if ( category == null )
208 {
209 if ( other.category != null )
210 {
211 return false;
212 }
213 }
214 else if ( !category.equals( other.category ) )
215 {
216 return false;
217 }
218 if ( name == null )
219 {
220 if ( other.name != null )
221 {
222 return false;
223 }
224 }
225 else if ( !name.equals( other.name ) )
226 {
227 return false;
228 }
229 if ( subsystem == null )
230 {
231 if ( other.subsystem != null )
232 {
233 return false;
234 }
235 }
236 else if ( !subsystem.equals( other.subsystem ) )
237 {
238 return false;
239 }
240 return true;
241 }
242
243 public String getName()
244 {
245 return name;
246 }
247
248 public String getCategory()
249 {
250 return category;
251 }
252
253 public String getSubsystem()
254 {
255 return subsystem;
256 }
257
258 }
259
260
261 /**
262 * Listener interface to get notified on montor events
263 */
264 public static interface Listener
265 {
266 void onStatValueRegistered( StatValue value );
267 }
268
269 /**
270 * Monitor that accepts Listeners and notify them on monitor events
271 */
272 public static interface Observable extends Monitor
273 {
274 /**
275 * @param listener listener to get registered
276 */
277 void addListener( Listener listener );
278
279 /**
280 * @param listener listener to get removed
281 */
282 void removeListener( Listener listener );
283 }
284 }