1 package edu.internet2.middleware.grouper.util;
2
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.LinkedHashMap;
6 import java.util.Map;
7
8 import org.apache.commons.logging.Log;
9
10 import edu.internet2.middleware.grouper.cfg.GrouperConfig;
11
12 public class PerformanceLogger {
13
14 public PerformanceLogger() {
15 }
16
17
18 private static final Log LOG = GrouperUtil.getLog(PerformanceLogger.class);
19
20
21
22
23 private static Map<String, ThreadLocal<Map<String, Object>>> performanceTiming = Collections.synchronizedMap(new HashMap<String, ThreadLocal<Map<String, Object>>>());
24
25
26
27
28
29
30
31 private static Map<String, Object> performanceTimingMap(String label, boolean createIfNotThere, boolean multiThreaded) {
32 ThreadLocal<Map<String, Object>> threadLocal = performanceTimingThreadLocal(label);
33 Map<String, Object> result = threadLocal.get();
34 if (result == null && createIfNotThere) {
35 result = new LinkedHashMap<String, Object>();
36 if (multiThreaded) {
37 result = Collections.synchronizedMap(result);
38 }
39 threadLocal.set(result);
40 }
41 return result;
42 }
43
44
45
46
47
48 public static Log performanceLog() {
49 return LOG;
50 }
51
52
53
54
55
56
57 public static void performanceTimingStart(String label, boolean multiThreaded) {
58 if (performanceTimingEnabled(label)) {
59 performanceTimingMap(label, true, multiThreaded);
60 performanceTimingData(label, "performanceLogFor", label);
61 performanceTimingData(label, "startNanos", System.nanoTime());
62 } else {
63 performanceTimingDelete(label);
64 }
65 }
66
67
68
69
70
71
72 private static ThreadLocal<Map<String, Object>> performanceTimingThreadLocal(String label) {
73 ThreadLocal<Map<String, Object>> threadLocal = performanceTiming.get(label);
74 if (threadLocal == null) {
75 synchronized (PerformanceLogger.class) {
76 threadLocal = performanceTiming.get(label);
77 if (threadLocal == null) {
78 threadLocal = new InheritableThreadLocal<Map<String, Object>>();
79 performanceTiming.put(label, threadLocal);
80 }
81 }
82 }
83 return threadLocal;
84 }
85
86
87
88
89
90 public static void performanceTimingDelete(String label) {
91 ThreadLocal<Map<String, Object>> threadLocal = performanceTimingThreadLocal(label);
92 threadLocal.remove();
93 }
94
95
96
97
98
99 public static void performanceTimingGate(String label, String key) {
100 try {
101 Map<String, Object> performanceMap = performanceTimingMap(label, false, false);
102 if (performanceMap == null) {
103 return;
104 }
105 Long startNanos = (Long)performanceMap.get("startNanos");
106 if (startNanos == null) {
107 throw new RuntimeException("Performance timeer is not started!");
108 }
109 String newKey = key + "_elapsedMs";
110 String keyCount = key + "_count";
111
112 Long originalMillis = (Long)performanceMap.get(newKey);
113 Integer count = (Integer)performanceMap.get(keyCount);
114
115 if (originalMillis != null) {
116 if (count == null) {
117 count = 1;
118 }
119 count++;
120 performanceMap.put(keyCount, count);
121
122 return;
123
124 }
125 originalMillis = (System.nanoTime()-startNanos)/1000000;
126
127 performanceMap.put(newKey, originalMillis);
128 } catch (Exception e) {
129 LOG.error("Error with " + key, e);
130 }
131
132 }
133
134
135
136
137
138
139 public static void performanceTimingAllDuration(String key, long durationNanos) {
140
141 try {
142 for (String label : performanceTiming.keySet()) {
143
144 performanceTimingDuration(label, key, durationNanos);
145
146 }
147 } catch (Exception e) {
148 LOG.error("Error with " + key, e);
149 }
150 }
151
152
153
154
155 public static final String PERFORMANCE_LOG_LABEL_SQL = "sqlQueries";
156
157
158
159
160
161
162 public static void performanceTimingDuration(String label, String key, long durationNanos) {
163 try {
164 Map<String, Object> performanceMap = performanceTimingMap(label, false, false);
165 if (performanceMap == null) {
166 return;
167 }
168
169 String durationKey = key + "_durationNanos";
170 String keyCount = key + "_count";
171
172 Long currentDuration = (Long)performanceMap.get(durationKey);
173 Integer count = (Integer)performanceMap.get(keyCount);
174
175 if (count != null) {
176 count++;
177 performanceMap.put(keyCount, count);
178 } else if (currentDuration != null) {
179 count = 2;
180 performanceMap.put(keyCount, count);
181 }
182
183 if (currentDuration != null) {
184 durationNanos += currentDuration;
185 }
186
187 performanceMap.put(durationKey, durationNanos);
188 } catch (Exception e) {
189 LOG.error("Error with " + key, e);
190 }
191
192 }
193
194
195
196
197
198
199 public static void performanceTimingData(String label, String key, Object value) {
200 try {
201 Map<String, Object> performanceMap = performanceTimingMap(label, false, false);
202 if (performanceMap == null) {
203 return;
204 }
205 performanceMap.put(key, value);
206 } catch (Exception e) {
207 LOG.error("Error with " + label + ", " + key, e);
208 }
209 }
210
211
212
213
214
215
216 public static boolean performanceTimingEnabled(String label) {
217 boolean performanceLog = GrouperConfig.retrieveConfig().propertyValueBoolean("grouper.log.performance.info.on." + label, false);
218 return performanceLog;
219 }
220
221
222
223
224
225
226 public static void performanceTimingDataRemoveKey(String label, String key) {
227 try {
228 Map<String, Object> performanceMap = performanceTimingMap(label, false, false);
229 if (performanceMap == null) {
230 return;
231 }
232 performanceMap.remove(key);
233 } catch (Exception e) {
234 LOG.error("Error with " + label + ", " + key, e);
235 }
236 }
237
238
239
240
241
242 public static String performanceTimingDataResult(String label) {
243 try {
244 Map<String, Object> performanceMap = performanceTimingMap(label, false, false);
245 if (performanceMap == null) {
246 return null;
247 }
248 PerformanceLogger.performanceTimingGate(label, "took");
249 performanceTimingDataRemoveKey(label, "startNanos");
250
251
252 Map<String, Object> performanceMapNew = new LinkedHashMap<String, Object>();
253 for (String key : performanceMap.keySet()) {
254 Object value = performanceMap.get(key);
255 if (value instanceof Long && key.endsWith("_durationNanos")) {
256 Long valueLong = (Long)value;
257 key = GrouperUtil.prefixOrSuffix(key, "_durationNanos", true) + "_durationMs";
258 valueLong /= 1000000;
259 value = valueLong;
260 }
261 performanceMapNew.put(key, value);
262 }
263
264 String result = GrouperUtil.mapToString(performanceMapNew);
265 PerformanceLogger.performanceTimingDelete(label);
266 return result;
267 } catch (Exception e) {
268 LOG.error("Error with " + label, e);
269 return null;
270 }
271
272 }
273
274
275
276 }