View Javadoc
1   package com.atlassian.plugin.instrumentation;
2   
3   import com.atlassian.instrumentation.operations.OpSnapshot;
4   import com.atlassian.instrumentation.operations.OpTimer;
5   import org.apache.log4j.MDC;
6   import org.slf4j.Logger;
7   import org.slf4j.LoggerFactory;
8   
9   import javax.annotation.Nonnull;
10  import java.util.Optional;
11  import java.util.concurrent.TimeUnit;
12  
13  /**
14   * Wrapper around an {@link com.atlassian.instrumentation.operations.OpTimer} that may be safely used even if that
15   * class is not present in the class loader.
16   * <p>
17   * This wrapper implements {@link java.io.Closeable}. On close it logs elapsed time and elapsed cpu time
18   * <p>
19   * Note to maintainers: extreme care must be taken to ensure that <code>OpTimer</code> not accessed at runtime if it is
20   * not present.
21   *
22   * @see PluginSystemInstrumentation
23   * @since 4.1
24   */
25  public class SingleTimer extends Timer {
26      private static final Logger log = LoggerFactory.getLogger(SingleTimer.class);
27      // We cannot rely on OpTimer name for logging as it contains timestamps
28      private String name;
29  
30      SingleTimer(@Nonnull Optional<OpTimer> opTimer, String name) {
31          super(opTimer);
32          this.name = name;
33      }
34  
35      public String getName() {
36          return name;
37      }
38      
39      /**
40       * End the timer, if instrumentation is present and enabled log clock time and cpu time
41       */
42      @Override
43      public void close() {
44          Optional<OpTimer> timerOption = this.getOpTimer();
45          if (timerOption.isPresent()) {
46              OpSnapshot snapshot = timerOption.get().snapshot();
47              long cpuTime = snapshot.getCpuTotalTime(TimeUnit.MILLISECONDS);
48              long elapsedTime = snapshot.getElapsedTotalTime(TimeUnit.MILLISECONDS);
49              String logKey = "com.atlassian.plugin." + name;
50              String cpuKey = logKey + ".cpu-ms";
51              String clockKey = logKey + ".clock-ms";
52  
53              MDC.put(cpuKey, cpuTime);
54              MDC.put(clockKey, elapsedTime);
55              // Kibana does not register DEBUG messages. This is safe as instrumentation won't be enabled in PROD
56              log.info("Timer {} took {}ms ({} cpu ns)", snapshot.getName(), elapsedTime, cpuTime);
57              MDC.remove(clockKey);
58              MDC.remove(cpuKey);
59          }
60          super.close();
61      }
62  }