All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.undefinedlabs.scope.statistics.Statistics Maven / Gradle / Ivy

package com.undefinedlabs.scope.statistics;

import com.undefinedlabs.scope.Span;
import com.undefinedlabs.scope.SpanContext;
import com.undefinedlabs.scope.context.SharedContextMap;
import com.undefinedlabs.scope.jdk.Supplier;
import com.undefinedlabs.scope.logger.ScopeLogger;
import com.undefinedlabs.scope.logger.ScopeLoggerLevel;
import com.undefinedlabs.scope.logger.ScopeLoggerResolver;
import com.undefinedlabs.scope.reporter.internal.remote.model.ScopeSpan;
import com.undefinedlabs.scope.settings.ScopeSettings;
import com.undefinedlabs.scope.settings.ScopeSettingsResolver;
import com.undefinedlabs.scope.utils.ThreadUtils;
import com.undefinedlabs.scope.utils.baggage.BaggageKeys;
import com.undefinedlabs.scope.utils.baggage.BaggageValues;
import com.undefinedlabs.scope.utils.tag.TagKeys;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

public enum Statistics {
  INSTANCE;

  private static final ScopeLogger LOGGER = ScopeLoggerResolver.INSTANCE.get();

  private final boolean traceEnabled =
      ScopeLoggerLevel.TRACE.equals(
          ScopeSettingsResolver.INSTANCE.get().getSetting(ScopeSettings.SCOPE_LOGGER_LEVEL));

  private final Map> conflictFilepathsByClassName = new HashMap<>();

  private final AtomicInteger runnerCachedTestCount = new AtomicInteger();
  private final List runnerCachedTest = new ArrayList<>();

  private final List coverageNotDetectedExecutableLines = new ArrayList<>();
  private final Map> coverageSessionChannelMismatch = new HashMap<>();
  private final Map> coverageNullOnMap = new HashMap<>();

  private final AtomicInteger startedCoverageSessions = new AtomicInteger();
  private final AtomicInteger finishedCoverageSessions = new AtomicInteger();
  private final Map startedCoverageSessionsStats =
      new HashMap<>();
  private final List finishedCoverageSessionsStats = new ArrayList<>();
  private final Map reportedCoverageLackOfSessionsPerThread =
      new HashMap<>();

  private final AtomicInteger reportedCoveragePayloadOnSessionClosed = new AtomicInteger();
  private final List reportedCoveragePayloadOnSessionClosedPayloads = new ArrayList<>();

  private final AtomicInteger reportedCoverageLackOfSession = new AtomicInteger();
  private final AtomicInteger reportedCoverageNoneSessionStarted = new AtomicInteger();

  private final AtomicInteger startedSpansAsTest = new AtomicInteger();
  private final AtomicInteger finishedSpansAsTest = new AtomicInteger();
  private final AtomicInteger startedSpans = new AtomicInteger();
  private final AtomicInteger finishedSpans = new AtomicInteger();

  private final AtomicInteger reportedSpans = new AtomicInteger();
  private final AtomicInteger reportedSpansOnTime = new AtomicInteger();

  private final AtomicInteger totalSentSpans = new AtomicInteger();
  private final AtomicInteger successSentSpans = new AtomicInteger();
  private final AtomicInteger failedSentSpans = new AtomicInteger();
  private final AtomicInteger submittedSendTasks = new AtomicInteger();
  private final AtomicInteger executedSendTasks = new AtomicInteger();

  private boolean processEndSentSuccess;

  private String branch;
  private boolean runnerActivation;

  private String logPathFile;
  private boolean coverageActivation;

  private long startScopeExecution;
  private long durationScopeExecution;

  private float throughputSubmittedSendTasks;
  private float throughputExecutedSendTasks;

  private int flushInterval;
  private int maxBufferSizeSpans;
  private int maxBufferSizeEvents;
  private int senderThreadsNum;
  private long senderCloseTimeoutMs;

  private final Map notFinishedSpans = new HashMap<>();
  private final Map reportedAfterOutOfTime = new HashMap<>();
  private final Map trackedStartedAfterOutOfTime = new HashMap<>();
  private final Map trackedFinishedAfterOutOfTime = new HashMap<>();
  private final Object lock = new Object();

  public void registerSourceCodeConflict(
      final Map> conflictFilepathsByClassName) {
    this.conflictFilepathsByClassName.putAll(conflictFilepathsByClassName);
  }

  public void registerSuccessSentProcessEnd() {
    synchronized (lock) {
      processEndSentSuccess = true;
    }
  }

  public void registerBranch(final String branch) {
    this.branch = branch;
  }

  public void registerRunnerCachedTest(
      final String platform, final String testSuite, final String testName) {
    runnerCachedTestCount.addAndGet(1);
    synchronized (runnerCachedTest) {
      runnerCachedTest.add(platform + "#" + testSuite + "#" + testName);
    }
  }

  public void registerRunnerActivation(final boolean runnerActivation) {
    this.runnerActivation = runnerActivation;
  }

  public void registerLogPathFile(final String logPathFile) {
    this.logPathFile = logPathFile;
  }

  public void registerCoveragePayloadOnSessionClosed(final String payload) {
    reportedCoveragePayloadOnSessionClosed.addAndGet(1);
    if (traceEnabled) {
      synchronized (reportedCoveragePayloadOnSessionClosedPayloads) {
        reportedCoveragePayloadOnSessionClosedPayloads.add(payload);
      }
    }
  }

  public void registerCoverageNotDetectedExecutableLines(final String className) {
    if (traceEnabled) {
      coverageNotDetectedExecutableLines.add(className);
    }
  }

  private void registerInThreadMap(
      final Map> threadMap,
      final Thread thread,
      final Supplier valueSupplier) {
    if (traceEnabled) {
      synchronized (threadMap) {
        final String threadId = ThreadUtils.getUniqueId(thread);
        final String value = valueSupplier.get();
        final Set valueStore = threadMap.get(threadId);
        if (valueStore == null) {
          final Set newValueStore = new HashSet<>();
          newValueStore.add(value);
          threadMap.put(threadId, newValueStore);
        } else {
          threadMap.get(threadId).add(value);
        }
      }
    }
  }

  public void registerCoverageSessionChannelMismatch(
      final Thread thread,
      final String activeSessionIdTls,
      final String activeSessionIdOnChannelRegistration) {
    if (traceEnabled) {
      registerInThreadMap(
          coverageSessionChannelMismatch,
          thread,
          new Supplier() {
            @Override
            public String get() {
              return "TLS ["
                  + activeSessionIdTls
                  + "] != ChannelReg ["
                  + activeSessionIdOnChannelRegistration
                  + "]";
            }
          });
    }
  }

  public void registerCoverageNullOnMap(final Thread thread, final SharedContextMap map) {
    if (traceEnabled) {
      registerInThreadMap(
          coverageNullOnMap,
          thread,
          new Supplier() {
            @Override
            public String get() {
              return map.getId();
            }
          });
    }
  }

  public void registerCoverageStartSession(final String sessionId, final Thread thread) {
    startedCoverageSessions.addAndGet(1);

    if (traceEnabled) {
      synchronized (startedCoverageSessionsStats) {
        startedCoverageSessionsStats.put(
            sessionId, new CoverageSessionStatistics(sessionId, ThreadUtils.getUniqueId(thread)));
      }
    }
  }

  public void registerCoverageEndSession(final String sessionId) {
    finishedCoverageSessions.addAndGet(1);

    if (traceEnabled) {
      synchronized (startedCoverageSessionsStats) {
        final CoverageSessionStatistics coverageStatistics =
            startedCoverageSessionsStats.remove(sessionId);
        if (coverageStatistics != null) {
          finishedCoverageSessionsStats.add(coverageStatistics);
        }
      }
    }
  }

  public void registerCoverageActivation(final boolean coverageActivation) {
    this.coverageActivation = coverageActivation;
  }

  public void registerCoverageOutOfSession(final Thread thread) {
    if (traceEnabled) {
      synchronized (startedCoverageSessionsStats) {
        if (startedCoverageSessionsStats.size() > 0) {
          final AtomicInteger reportedLackCoverage =
              reportedCoverageLackOfSessionsPerThread.get(ThreadUtils.getUniqueId(thread));
          if (reportedLackCoverage == null) {
            reportedCoverageLackOfSessionsPerThread.put(
                ThreadUtils.getUniqueId(thread), new AtomicInteger(1));
          } else {
            reportedLackCoverage.addAndGet(1);
          }
          reportedCoverageLackOfSession.addAndGet(1);
        } else {
          reportedCoverageNoneSessionStarted.addAndGet(1);
        }
      }
    }
  }

  public void registerCoverageOnSession(final String sessionId, final Thread thread) {
    if (traceEnabled) {
      synchronized (startedCoverageSessionsStats) {
        final CoverageSessionStatistics coverageSessionStatistics =
            startedCoverageSessionsStats.get(sessionId);
        if (coverageSessionStatistics == null) {
          LOGGER.warn("--- Coverage Session Statistics of '" + sessionId + "' is null. " + thread);
        } else {
          coverageSessionStatistics.registerCoverageOnSession(ThreadUtils.getUniqueId(thread));
        }
      }
    }
  }

  public void registerTrackStartedSpanOutOfTime(final Span span) {
    synchronized (lock) {
      trackedStartedAfterOutOfTime.put(span.context().toString(), span.getOperationName());
    }
  }

  public void registerTrackFinishedSpanOutOfTime(final Span span) {
    synchronized (lock) {
      trackedFinishedAfterOutOfTime.put(span.context().toString(), span.getOperationName());
    }
  }

  public void registerReportedSpanOnTime(final Span span) {
    if (!(span instanceof Span)) {
      return;
    }

    reportedSpansOnTime.addAndGet(1);
    reportedSpans.addAndGet(1);
  }

  public void registerReportedOutOfTime(final String context, final ScopeSpan scopeSpan) {
    synchronized (lock) {
      reportedAfterOutOfTime.put(context, scopeSpan);
    }

    reportedSpans.addAndGet(1);
  }

  public void registerStartedTestSpan(final io.opentracing.Span span) {
    if (!(span instanceof Span)) {
      return;
    }

    startedSpansAsTest.addAndGet(1);
  }

  public void registerFinishedTestSpan(final io.opentracing.Span span) {
    if (!(span instanceof Span)) {
      return;
    }

    finishedSpansAsTest.addAndGet(1);
  }

  public void registerStartedSpan(final io.opentracing.Span span) {
    if (!(span instanceof Span)) {
      return;
    }

    startedSpans.addAndGet(1);
    synchronized (lock) {
      notFinishedSpans.put(span.context().toString(), (Span) span);
    }
  }

  public void registerFinishedSpan(final io.opentracing.Span span) {
    if (!(span instanceof Span)) {
      return;
    }

    finishedSpans.addAndGet(1);
    synchronized (lock) {
      notFinishedSpans.remove(span.context().toString());
    }
  }

  public void registerSuccessSentSpans(final List scopeSpans) {
    successSentSpans.addAndGet(scopeSpans.size());
    totalSentSpans.addAndGet(scopeSpans.size());
  }

  public void registerFailedSentSpans(final List scopeSpans) {
    failedSentSpans.addAndGet(scopeSpans.size());
    totalSentSpans.addAndGet(scopeSpans.size());
  }

  public void registerSendTaskPlanned() {
    submittedSendTasks.addAndGet(1);
  }

  public void registerSendTaskExecuted() {
    executedSendTasks.addAndGet(1);
  }

  public void registerStartScopeExecution() {
    startScopeExecution = System.currentTimeMillis();
  }

  public void registerFinishScopeExecution() {
    durationScopeExecution = System.currentTimeMillis() - startScopeExecution;

    throughputSubmittedSendTasks =
        (float) submittedSendTasks.get() / ((float) durationScopeExecution / 1000);
    throughputExecutedSendTasks =
        (float) executedSendTasks.get() / ((float) durationScopeExecution / 1000);
  }

  public void registerHealthCheckInterval(final int flushInterval) {
    this.flushInterval = flushInterval;
  }

  public void registerMaxBufferSizeSpans(final int maxBufferSizeSpans) {
    this.maxBufferSizeSpans = maxBufferSizeSpans;
  }

  public void registerMaxBufferSizeEvents(final int maxBufferSizeEvents) {
    this.maxBufferSizeEvents = maxBufferSizeEvents;
  }

  public void registerSenderThreadsNum(final int senderThreadsNum) {
    this.senderThreadsNum = senderThreadsNum;
  }

  public void registerSenderCloseTimeoutMs(final long senderCloseTimeoutMs) {
    this.senderCloseTimeoutMs = senderCloseTimeoutMs;
  }

  public String getReport() {
    synchronized (lock) {
      final Collection notFinishedSpans = this.notFinishedSpans.values();

      final StringBuilder sb = new StringBuilder();
      sb.append("\n-- Statistics --");
      sb.append("\n---- Source Code Filepath conflicts: ")
          .append(conflictFilepathsByClassName.size());
      if (traceEnabled && conflictFilepathsByClassName.size() > 0) {
        for (final Map.Entry> entry : conflictFilepathsByClassName.entrySet()) {
          sb.append("\n-------- ").append(entry.getKey());
          for (final String conflict : entry.getValue()) {
            sb.append("\n------------ ").append(conflict);
          }
        }
      }

      sb.append("\n---- Reporter Buffer Size Spans: ").append(maxBufferSizeSpans).append(" spans.");
      sb.append("\n---- Reporter Buffer Size Events: ")
          .append(maxBufferSizeEvents)
          .append(" events.");
      sb.append("\n---- Reporter Flush Interval: ").append(flushInterval).append(" ms.");
      sb.append("\n---- Sender Threads Num: ").append(senderThreadsNum).append(" threads.");
      sb.append("\n---- Sender Close Timeout: ").append(senderCloseTimeoutMs).append(" ms.");
      sb.append("\n---- Runner [branch: ")
          .append(branch)
          .append("]: ")
          .append((runnerActivation ? "enabled" : "disabled"));
      if (runnerActivation) {
        sb.append("\n-------- Total Cached Tests: ").append(runnerCachedTestCount.get());
        for (final String cachedTest : runnerCachedTest) {
          sb.append("\n----------- ").append(cachedTest);
        }
      }
      sb.append("\n---- Coverage: ").append((coverageActivation ? "enabled" : "disabled"));
      if (coverageActivation) {
        sb.append("\n---- Total Coverage Sessions Started: ").append(startedCoverageSessions);
        sb.append("\n---- Total Coverage Sessions Finished: ").append(finishedCoverageSessions);

        if (traceEnabled) {
          sb.append("\n---- Total Coverage Payloads On Session Closed: ")
              .append(reportedCoveragePayloadOnSessionClosed);
          for (final String payload : reportedCoveragePayloadOnSessionClosedPayloads) {
            sb.append("\n-------- ").append(payload);
          }

          for (final CoverageSessionStatistics coverageSessionStatistics :
              finishedCoverageSessionsStats) {
            sb.append("\n-------- ")
                .append("Coverage Session Id: ")
                .append(coverageSessionStatistics.getSessionId())
                .append(".");
            sb.append("\n----------- ")
                .append("Coverage Payloads: ")
                .append(coverageSessionStatistics.getRegisteredCoverageOnSession())
                .append(".");
            sb.append("\n----------- ").append("Coverage Session on Threads:");
            for (final String threadDesc : coverageSessionStatistics.getThreadsDescriptions()) {
              sb.append("\n-------------- ").append(threadDesc);
            }
          }
          sb.append("\n---- Total Coverage Sessions Not Finished: ")
              .append(startedCoverageSessionsStats.size());
          for (final CoverageSessionStatistics coverageSessionStatistics :
              startedCoverageSessionsStats.values()) {
            sb.append("\n-------- ")
                .append("Coverage Session Id: ")
                .append(coverageSessionStatistics.getSessionId())
                .append(".");
            sb.append("\n----------- ")
                .append("Coverage Payloads: ")
                .append(coverageSessionStatistics.getRegisteredCoverageOnSession())
                .append(".");
            sb.append("\n----------- ").append("Coverage Session on Threads:");
            for (final String threadDesc : coverageSessionStatistics.getThreadsDescriptions()) {
              sb.append("\n-------------- ").append(threadDesc);
            }
          }

          sb.append("\n---- Coverage Orphan - Required Session: ")
              .append(reportedCoverageLackOfSession)
              .append(" payloads");
          for (final Map.Entry entry :
              reportedCoverageLackOfSessionsPerThread.entrySet()) {
            sb.append("\n-------- ")
                .append(entry.getKey())
                .append(": ")
                .append(entry.getValue())
                .append(" payloads");
          }
          sb.append("\n---- Coverage Orphan - Not Required Session: ")
              .append(reportedCoverageNoneSessionStarted)
              .append(" payloads.");
          sb.append("\n---- Coverage Not Detected Exec Lines:");
          for (final String classname : coverageNotDetectedExecutableLines) {
            sb.append("\n-------- ").append(classname);
          }

          if (coverageSessionChannelMismatch.size() > 0) {
            sb.append("\n---- Coverage Session Mismatch (TLS vs Channel)");
            for (final Map.Entry> entry :
                coverageSessionChannelMismatch.entrySet()) {
              sb.append("\n-------- ").append(entry.getKey());
              for (final String message : entry.getValue()) {
                sb.append("\n------------ ").append(message);
              }
            }
          }
        }
      }
      sb.append("\n---- LogPath File: ").append(logPathFile);
      sb.append("\n---- Process End Sent: ").append(processEndSentSuccess);
      sb.append("\n---- Total Duration: ").append(durationScopeExecution).append(" ms.");
      sb.append("\n---- Test Spans Started: ").append(startedSpansAsTest.get());
      sb.append("\n---- Test Spans Finished: ").append(finishedSpansAsTest.get());
      sb.append("\n---- Total Spans Started: ").append(startedSpans.get());
      sb.append("\n---- Total Spans Finished: ").append(finishedSpans.get());
      sb.append("\n---- Total Spans Reported: ").append(reportedSpans.get());
      sb.append("\n---- Total Spans Reported (On Time): ").append(reportedSpansOnTime.get());
      sb.append("\n---- Total Spans Reported (Out Of Time): ")
          .append(reportedAfterOutOfTime.size());
      if (reportedAfterOutOfTime.size() > 0) {
        for (final Map.Entry entry : reportedAfterOutOfTime.entrySet()) {
          sb.append("\n-------- [")
              .append(entry.getKey())
              .append("] operation=")
              .append(entry.getValue().getOperation());
        }
      }
      sb.append("\n---- Total Started Spans tracked (Out Of Time): ")
          .append(trackedStartedAfterOutOfTime.size());
      if (trackedStartedAfterOutOfTime.size() > 0) {
        for (final Map.Entry entry : trackedStartedAfterOutOfTime.entrySet()) {
          sb.append("\n-------- [")
              .append(entry.getKey())
              .append("] operation=")
              .append(entry.getValue());
        }
      }
      sb.append("\n---- Total Finished Spans tracked (Out Of Time): ")
          .append(trackedFinishedAfterOutOfTime.size());
      if (trackedFinishedAfterOutOfTime.size() > 0) {
        for (final Map.Entry entry : trackedFinishedAfterOutOfTime.entrySet()) {
          sb.append("\n-------- [")
              .append(entry.getKey())
              .append("] operation=")
              .append(entry.getValue());
        }
      }
      sb.append("\n---- Total Send Tasks Submitted: ").append(submittedSendTasks.get());
      sb.append("\n---- Total Send Tasks Executed: ").append(executedSendTasks.get());
      sb.append("\n---- Throughput Send Tasks Submitted: ")
          .append(throughputSubmittedSendTasks)
          .append(" tasks/sec");
      sb.append("\n---- Throughput Send Tasks Executed: ")
          .append(throughputExecutedSendTasks)
          .append(" tasks/sec");
      sb.append("\n---- Total Spans Sent: ").append(totalSentSpans.get());
      sb.append("\n---- Total Spans Sent Success: ").append(successSentSpans.get());
      sb.append("\n---- Total Spans Sent Failed: ").append(failedSentSpans.get());
      sb.append("\n---- Total Spans Not Finished: ").append(notFinishedSpans.size());
      int i = 1;
      for (final Span span : notFinishedSpans) {
        final String traceKind = span.getBaggageItem(BaggageKeys.TRACE_KIND);
        final String parentId = ((SpanContext) span.context()).toParentSpanId();
        final boolean isTestSpan =
            parentId == null && BaggageValues.TRACE_KIND_TEST.equals(traceKind);

        sb.append("\n" + i + "-------- ")
            .append(span.getOperationName())
            .append(", ")
            .append("IsTestSpan: ")
            .append(isTestSpan)
            .append(", ")
            .append(span.getTags().get(TagKeys.Test.TEST_SUITE))
            .append("#")
            .append(span.getTags().get(TagKeys.Test.TEST_NAME))
            .append(" [")
            .append(span.context())
            .append("]");

        i += 1;
      }

      return sb.toString();
    }
  }

  protected void cleanUp() {
    synchronized (lock) {
      processEndSentSuccess = false;
      coverageActivation = false;
      runnerActivation = false;
      startedSpansAsTest.set(0);
      finishedSpansAsTest.set(0);
      startedSpans.set(0);
      finishedSpans.set(0);
      successSentSpans.set(0);
      failedSentSpans.set(0);
      totalSentSpans.set(0);
      submittedSendTasks.set(0);
      executedSendTasks.set(0);
      reportedSpans.set(0);
      reportedSpansOnTime.set(0);
      startScopeExecution = 0L;
      reportedCoveragePayloadOnSessionClosed.set(0);
      durationScopeExecution = 0L;
      throughputSubmittedSendTasks = 0.0F;
      throughputExecutedSendTasks = 0.0F;
      flushInterval = 0;
      maxBufferSizeSpans = 0;
      maxBufferSizeEvents = 0;
      senderThreadsNum = 0;
      senderCloseTimeoutMs = 0;
      reportedAfterOutOfTime.clear();
      notFinishedSpans.clear();
      runnerCachedTest.clear();
      runnerCachedTestCount.set(0);
      trackedStartedAfterOutOfTime.clear();
      trackedFinishedAfterOutOfTime.clear();
      conflictFilepathsByClassName.clear();
      reportedCoveragePayloadOnSessionClosedPayloads.clear();
    }
  }

  protected AtomicInteger getStartedSpansAsTest() {
    return startedSpansAsTest;
  }

  protected AtomicInteger getFinishedSpansAsTest() {
    return finishedSpansAsTest;
  }

  protected AtomicInteger getStartedSpans() {
    return startedSpans;
  }

  protected AtomicInteger getFinishedSpans() {
    return finishedSpans;
  }

  protected Map getNotFinishedSpans() {
    return notFinishedSpans;
  }

  public AtomicInteger getFailedSentSpans() {
    return failedSentSpans;
  }

  public AtomicInteger getTotalSentSpans() {
    return totalSentSpans;
  }

  public AtomicInteger getSuccessSentSpans() {
    return successSentSpans;
  }

  public Integer getNotFinishedSpansNum() {
    return getNotFinishedSpans().keySet().size();
  }

  public String getLogPathFile() {
    return logPathFile;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy