1 17 18 package org.sape.carbon.services.instrumentation.statistics; 19 20 import org.apache.commons.logging.Log; 21 import org.apache.commons.logging.LogFactory; 22 23 import java.io.Serializable ; 24 import java.lang.reflect.Method ; 25 import java.util.ArrayList ; 26 import java.util.Collection ; 27 import java.util.Collections ; 28 import java.util.HashMap ; 29 import java.util.HashSet ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import java.util.Map ; 33 34 import org.sape.carbon.core.component.Component; 35 import org.sape.carbon.core.component.FunctionalInterface; 36 import org.sape.carbon.core.component.proxy.Interceptor; 37 import org.sape.carbon.core.component.proxy.Invocation; 38 import org.sape.carbon.core.util.reflection.ClassTree; 39 import org.sape.carbon.core.util.reflection.ClassTree.ClassTreeNode; 40 41 67 public class DefaultStatisticsInterceptor 68 implements StatisticsInterceptor, Interceptor { 69 70 71 private Log log = 72 LogFactory.getLog(this.getClass()); 73 74 89 private Map methodStats = Collections.synchronizedMap(new HashMap ()); 90 91 96 private ThreadLocal localMethodStats = new ThreadLocal () { 97 protected Object initialValue() { 98 return new HashMap (); 99 } 100 }; 101 102 105 private long componentStartTime = System.currentTimeMillis(); 106 107 111 private long statisticsStartTime = System.currentTimeMillis(); 112 113 116 private Component componentReference; 117 118 121 private FunctionalInterface functionalImplementation; 122 123 126 protected Interceptor nextInterceptor; 127 128 132 private DefaultStatisticsInterceptor() { } 133 134 135 142 public DefaultStatisticsInterceptor( 143 FunctionalInterface functionalImplementation) { 144 145 this.functionalImplementation = functionalImplementation; 146 } 147 148 152 public long getStartTime() { 153 return this.componentStartTime; 154 } 155 156 161 public java.util.Date getStartDate() { 162 return new java.util.Date (getStartTime()); 163 } 164 165 170 public long getCallCounts() { 171 long totalCalls = 0L; 172 173 synchronized (this.methodStats) { 174 for (Iterator methodIterator = this.methodStats.entrySet().iterator(); methodIterator.hasNext();) { 175 Map.Entry entry = (Map.Entry ) methodIterator.next(); 176 List methodList = (List ) entry.getValue(); 177 178 for (int i = 0; i < methodList.size(); i++) { 179 MethodStats methodStats = (MethodStats) methodList.get(i); 180 totalCalls += methodStats.getCallCount(); 181 } 182 } 183 } 184 return totalCalls; 185 } 186 187 194 public synchronized Collection getMethodStats() { 195 Collection methodStatCollection = new HashSet (); 196 synchronized (this.methodStats) { 197 for (Iterator methodIterator = this.methodStats.entrySet().iterator(); methodIterator.hasNext();) { 198 Map.Entry entry = (Map.Entry ) methodIterator.next(); 199 Method method = (Method ) entry.getKey(); 200 List methodList = (List ) entry.getValue(); 201 202 MethodStats masterStats = new MethodStats(method); 203 for (int i = 0; i < methodList.size(); i++) { 204 MethodStats methodStats = (MethodStats) methodList.get(i); 205 masterStats.setCallCount(masterStats.getCallCount() + methodStats.getCallCount()); 206 masterStats.setFailures(masterStats.getFailures() + methodStats.getFailures()); 207 masterStats.setTotalExecutionDuration(masterStats.getTotalExecutionDuration() + methodStats.getTotalExecutionDuration()); 208 } 209 methodStatCollection.add(masterStats); 210 } 211 } 212 return methodStatCollection; 213 } 214 215 219 public void logStats() { 220 StringBuffer buf = new StringBuffer (); 221 buf.append("Statistics for component["); 222 buf.append(this.functionalImplementation.getClass().getName()); 223 buf.append("]:"); 224 225 Collection methodStats = getMethodStats(); 226 Iterator methodStatsIterator = methodStats.iterator(); 227 while (methodStatsIterator.hasNext()) { 228 MethodStats methodStat = (MethodStats) methodStatsIterator.next(); 229 buf.append("Method ["); 230 buf.append(methodStat.getMethod().getName()); 231 buf.append("] - "); 232 buf.append(methodStats.toString()); 233 } 234 log.info(buf.toString()); 235 } 236 237 242 public void setNextInterceptor(Interceptor interceptor) { 243 this.nextInterceptor = interceptor; 244 } 245 246 254 public Class [] getExposedInterfaces() { 255 return new Class [] {StatisticsInterceptor.class}; 256 } 257 258 267 public Object invoke(Invocation invocation) throws Throwable { 268 269 boolean trackable = invocation.isTargetFunctionalImplementation(); 270 271 MethodStats stats = null; 272 273 274 if (trackable) { 275 276 Map localMap = (Map ) this.localMethodStats.get(); 277 278 Method method = invocation.getMethod(); 279 stats = (MethodStats) localMap.get(method); 280 if (stats == null) { 281 synchronized(this) { 282 stats = new MethodStats(method); 283 localMap.put(method, stats); 284 List methodList = (List ) methodStats.get(method); 285 if (methodList == null) { 286 methodList = new ArrayList (); 287 this.methodStats.put(method,methodList); 288 } 289 methodList.add(stats); 290 } 291 } 292 stats.startMethodCall(System.currentTimeMillis()); 293 } 294 295 try { 296 297 Object result = this.nextInterceptor.invoke(invocation); 298 if (trackable) { 299 stats.endMethodCall(System.currentTimeMillis()); 300 } 301 return result; 302 } catch (Throwable t) { 303 304 if (trackable) { 305 stats.fail(); 306 } 307 throw t; 309 } 310 } 311 312 316 public void setComponentReference(Component component) { 317 this.componentReference = component; 318 } 319 320 333 public String getStatsReport() { 334 335 long statsTrackingTime = 336 System.currentTimeMillis() - this.statisticsStartTime; 337 338 StringBuffer buf = new StringBuffer (256); 339 buf.append("<html><body><h2>Instrumentation Report</h2>\n"); 340 buf.append("<b>Component: </b>"); 341 buf.append(this.componentReference.getComponentName()); 342 buf.append("<br>\n"); 343 344 buf.append(" <b>Service Type: </b>"); 345 buf.append(this.functionalImplementation.getClass().getName()); 346 buf.append("<br>\n"); 347 348 buf.append(" <b>Started: </b>"); 349 buf.append(getStartDate().toString()); 350 buf.append("<br>\n"); 351 352 buf.append(" <b>Calls: </b>"); 353 buf.append(getCallCounts()); 354 buf.append("<p>\n"); 355 356 357 buf.append("<b>Methods:</b><br>"); 358 buf.append("<table border='2'><tr> <td><b>Name</b></td> "); 359 buf.append("<td><b>Calls</b></td> <td><b>Total Duration</b></td> "); 360 buf.append("<td><b>Average Duration</b></td> "); 361 buf.append("<td><b>Failures</b></td> </tr>\n"); 362 Collection methodStats = getMethodStats(); 363 Iterator methodStatsIterator = methodStats.iterator(); 364 while (methodStatsIterator.hasNext()) { 365 MethodStats methodStat = (MethodStats) methodStatsIterator.next(); 366 367 buf.append("<tr> <td>"); 368 buf.append(methodStat.getMethod().getName()); 369 buf.append("</td> <td>"); 370 buf.append(methodStat.getCallCount()); 371 buf.append("</td> <td>"); 372 buf.append(methodStat.getTotalExecutionDuration()); 373 buf.append("</td> <td>"); 374 buf.append( 375 ((double) methodStat.getTotalExecutionDuration()) 376 / methodStat.getCallCount()); 377 378 buf.append("ms</td> <td>"); 379 buf.append(methodStat.getFailures()); 380 buf.append("</td> </tr>\n"); 381 } 382 buf.append("</table><p>"); 383 384 buf.append("<b>Generalizations:</b><br>"); 385 ClassTree tree = new ClassTree(this.componentReference.getClass()); 386 buf.append("<pre>\n"); 387 buf.append("<pre>\n"); 388 389 List list = tree.getOrderedList(); 390 for (int i = 0; i < list.size(); i++) { 391 Class aClass = (Class ) list.get(i); 392 buf.append("+ " + aClass.toString() + "\n"); 393 } 394 395 buf.append("</body></html>"); 396 397 return buf.toString(); 398 } 399 400 408 private void appendClassInfo(StringBuffer buf, ClassTreeNode node, 409 int depth) { 410 411 for (int i = 0; i < depth; i++) { 412 buf.append(" "); 413 } 414 buf.append("+ "); 415 buf.append(node.getObjectClass()); 416 buf.append("\n"); 417 for (Iterator iterator = node.getChildren().iterator(); 418 iterator.hasNext();) { 419 420 ClassTreeNode child = (ClassTreeNode) iterator.next(); 421 appendClassInfo(buf, child, depth + 1); 422 } 423 } 424 425 428 public void resetStats() { 429 synchronized (this.methodStats) { 430 this.methodStats.clear(); 431 } 432 this.statisticsStartTime = 0L; 433 } 434 435 449 public static class MethodStats implements Serializable { 450 451 private Method method; 452 453 454 private long callCount = 0; 455 456 457 private long failures = 0; 458 459 460 private long totalExecutionDuration = 0; 461 462 468 private final ThreadLocal methodCall = new ThreadLocal () { 469 protected synchronized Object initialValue() { 470 return new Long (-1L); 471 } 472 }; 473 474 475 479 public MethodStats(Method method) { 480 this.method = method; 481 } 482 483 490 public void startMethodCall(final long time) { 491 this.callCount++; 492 493 if ((this.methodCall.get() == null) 496 || ((Long ) this.methodCall.get()).longValue() < 0L) { 497 498 this.methodCall.set(new Long (time)); 499 } else { 500 this.failures++; 501 } 502 } 503 504 507 public void fail() { 508 this.failures++; 509 this.methodCall.set(new Long (-1L)); 510 } 511 512 517 public void endMethodCall(long time) { 518 long duration = time - ((Long ) this.methodCall.get()).longValue(); 519 this.totalExecutionDuration += duration; 520 this.methodCall.set(new Long (-1L)); 521 } 522 523 527 public Method getMethod() { 528 return this.method; 529 } 530 531 535 public long getCallCount() { 536 return this.callCount; 537 } 538 539 544 public long getFailures() { 545 return this.failures; 546 } 547 548 556 public long getTotalExecutionDuration() { 557 return this.totalExecutionDuration; 558 } 559 560 protected void setCallCount(long callCount) { 561 this.callCount = callCount; 562 } 563 564 protected void setFailures(long failures) { 565 this.failures = failures; 566 } 567 568 protected void setTotalExecutionDuration(long totalExecutionDuration) { 569 this.totalExecutionDuration = totalExecutionDuration; 570 } 571 572 577 public String toString() { 578 StringBuffer buffer = new StringBuffer (); 579 580 buffer.append("Method Statistics("); 581 buffer.append(this.method.getName()); 582 buffer.append(") Calls: "); 583 buffer.append(getCallCount()); 584 buffer.append(" Duration: "); 585 buffer.append(this.getTotalExecutionDuration()); 586 buffer.append(" Failures: "); 587 buffer.append(this.getFailures()); 588 589 return buffer.toString(); 590 } 591 592 } 593 } 594 | Popular Tags |