com.undefinedlabs.scope.ScopeAgent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scope-agent Show documentation
Show all versions of scope-agent Show documentation
Scope is a APM for tests to give engineering teams unprecedented visibility into their CI process to quickly identify, troubleshoot and fix failed builds.
The Scope Java agent allows to instrument the tests executions and send the results to your Scope instance.
package com.undefinedlabs.scope;
import com.undefinedlabs.scope.bootstrap.ContextStrategy;
import com.undefinedlabs.scope.bootstrap.ContextTrampoline;
import com.undefinedlabs.scope.coverage.GlobalCoverageReporter;
import com.undefinedlabs.scope.coverage.instrumentation.CoverageAgentBuilderCreator;
import com.undefinedlabs.scope.coverage.reporter.impl.CoverageReporterImplFactory;
import com.undefinedlabs.scope.coverage.rules.ScopeCoverageAgentRule;
import com.undefinedlabs.scope.initializers.Initializer;
import com.undefinedlabs.scope.initializers.InitializersResolver;
import com.undefinedlabs.scope.initializers.ScopeInitializersResolver;
import com.undefinedlabs.scope.logger.ScopeLogger;
import com.undefinedlabs.scope.logger.ScopeLoggerResolver;
import com.undefinedlabs.scope.rules.*;
import com.undefinedlabs.scope.runner.ScopeGlobalRunner;
import com.undefinedlabs.scope.runner.ScopeRunnerFilter;
import com.undefinedlabs.scope.runner.impl.ScopeRunnerImplFactory;
import com.undefinedlabs.scope.runner.rules.ScopeRunnerAgentRule;
import com.undefinedlabs.scope.settings.ScopeSettings;
import com.undefinedlabs.scope.settings.ScopeSettingsResolver;
import com.undefinedlabs.scope.settings.credentials.CredentialsUtils;
import com.undefinedlabs.scope.settings.credentials.ScopeCredentials;
import com.undefinedlabs.scope.settings.remote.ScopeRemoteSettings;
import com.undefinedlabs.scope.settings.remote.ScopeRemoteSettingsResolver;
import com.undefinedlabs.scope.statistics.Statistics;
import com.undefinedlabs.scope.utils.ResourceUtils;
import com.undefinedlabs.scope.utils.StringUtils;
import com.undefinedlabs.scope.utils.props.SystemProps;
import com.undefinedlabs.scope.utils.reports.ReportURLUtils;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;
import net.bytebuddy.agent.builder.AgentBuilder;
import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;
public class ScopeAgent {
private static final ScopeLogger LOG = ScopeLoggerResolver.INSTANCE.get();
private final TracerRegister tracerRegisterAsGlobalTracer;
private final Tracer tracer;
private final ScopeSettings settings;
private final ScopeRemoteSettings remoteSettings;
private final InitializersResolver initializersResolver;
private final AgentRulesResolver agentRulesResolver;
private final CoverageAgentRulesResolver coverageAgentRulesResolver;
private final RunnerAgentRulesResolver runnerAgentRulesResolver;
private final AgentBuilder coverageInstrumentation;
private final Instrumentation instrumentation;
private static Boolean initialized = Boolean.FALSE;
public static void premain(final String arg, final Instrumentation instrumentation) throws Exception {
synchronized (initialized) {
if (!initialized) {
instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(ResourceUtils.INSTANCE.getResourceAsTempFile("bootstrap.jar")));
checkLoadedByBootstrapClassloader(ContextStrategy.class);
checkLoadedByBootstrapClassloader(ContextTrampoline.class);
final ScopeSettings settings = ScopeSettingsResolver.INSTANCE.get();
final ScopeRemoteSettings remoteSettings = ScopeRemoteSettingsResolver.INSTANCE.get(settings);
settings.printSettings(LOG);
remoteSettings.printSettings(LOG);
final ScopeAgent scopeAgent = new ScopeAgent(
ScopeTracerCreator.INSTANCE,
ScopeTracerRegisterAsGlobalTracer.INSTANCE,
ScopeInitializersResolver.INSTANCE,
ScopeAgentRulesResolver.INSTANCE,
ScopeCoverageAgentRulesResolver.INSTANCE,
ScopeRunnerAgentRulesResolver.INSTANCE,
settings,
remoteSettings,
CoverageAgentBuilderCreator.INSTANCE.create(),
instrumentation);
final Tracer localTracer = scopeAgent.execute();
System.setProperty(ScopeSettings.SCOPE_AGENT_IS_EXECUTING, "true");
final String logPathFile = Statistics.INSTANCE.getLogPathFile();
if (localTracer != null) {
LOG.info("** ScopeAgent started [ " + SystemProps.AGENT_ID + " ] **");
Statistics.INSTANCE.registerStartScopeExecution();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
final boolean mustSetGlobalTracer = (boolean) settings.getSetting(ScopeSettings.SCOPE_TRACER_GLOBAL);
final boolean isAutoInstrument = (boolean) settings.getSetting(ScopeSettings.SCOPE_INSTRUMENTATION_ENABLED);
final boolean testingMode = (boolean) settings.getSetting(ScopeSettings.SCOPE_TESTING_MODE);
if (mustSetGlobalTracer && isAutoInstrument) {
ScopeGlobalTracer.get().close();
} else {
localTracer.close();
}
Statistics.INSTANCE.registerFinishScopeExecution();
final String statisticsReport = Statistics.INSTANCE.getReport();
final int totalSent = Statistics.INSTANCE.getTotalSentSpans().get();
final int failedSent = Statistics.INSTANCE.getFailedSentSpans().get();
final int notFinished = Statistics.INSTANCE.getNotFinishedSpansNum();
if (testingMode && totalSent > 0) {
final ScopeCredentials credentials = CredentialsUtils.INSTANCE.extractFromDSN((String) ScopeSettingsResolver.INSTANCE.get().getSetting(ScopeSettings.SCOPE_DSN));
System.out.println("\n** Scope Test Report **\n");
if (failedSent == 0 && notFinished == 0) {
System.out.println("Access the detailed test report for this build at:");
System.out.println("\t" + ReportURLUtils.INSTANCE.getReportURL(credentials.getApiEndpoint(), SystemProps.AGENT_ID));
} else if (failedSent > 0 && notFinished == 0) {
System.out.println("There was a problem sending data to Scope.");
if (totalSent > failedSent) {
System.out.println("Partial results for this build are available at:");
System.out.println("\t" + ReportURLUtils.INSTANCE.getReportURL(credentials.getApiEndpoint(), SystemProps.AGENT_ID));
}
System.out.println("Check the agent logs at " + logPathFile + " for more information.\n\n");
} else if (failedSent == 0 && notFinished > 0) {
System.out.println("There was a problem capturing data from Scope Agent.");
System.out.println("Partial results for this build can be available at:");
System.out.println("\t" + ReportURLUtils.INSTANCE.getReportURL(credentials.getApiEndpoint(), SystemProps.AGENT_ID));
System.out.println("Check the agent logs at " + logPathFile + " for more information.\n\n");
}
}
LOG.info("** ScopeAgent finished [ " + SystemProps.AGENT_ID + " ] **");
LOG.debug(statisticsReport);
}
});
} else {
if (StringUtils.isEmpty((String) ScopeSettingsResolver.INSTANCE.get().getSetting(ScopeSettings.SCOPE_DSN))) {
System.out.println("SCOPE_DSN not defined, test results will not be sent to Scope.");
System.out.println("Developing locally? Try out Scratchpad! https://app.scope.dev/local-dev/");
} else {
System.out.println("ScopeAgent could not be started successfully.");
System.out.println("Check the agent logs at " + logPathFile + " for more information.\n\n");
}
}
initialized = Boolean.TRUE;
}
}
}
protected ScopeAgent(final TracerCreator tracerCreator,
final TracerRegister tracerRegisterAsGlobalTracer,
final InitializersResolver initializersResolver,
final AgentRulesResolver agentRulesResolver,
final CoverageAgentRulesResolver coverageAgentRulesResolver,
final RunnerAgentRulesResolver runnerAgentRulesResolver,
final ScopeSettings settings,
final ScopeRemoteSettings remoteSettings,
final AgentBuilder coverageInstrumentation,
final Instrumentation instrumentation) {
this.tracerRegisterAsGlobalTracer = tracerRegisterAsGlobalTracer;
this.tracer = tracerCreator.create(settings);
this.settings = settings;
this.remoteSettings = remoteSettings;
this.initializersResolver = initializersResolver;
this.agentRulesResolver = agentRulesResolver;
this.coverageAgentRulesResolver = coverageAgentRulesResolver;
this.runnerAgentRulesResolver = runnerAgentRulesResolver;
this.coverageInstrumentation = coverageInstrumentation;
this.instrumentation = instrumentation;
}
protected Tracer execute() {
if (this.tracer == null) {
return null;
}
ScopeGlobalTracer.registerIfAbsent(this.tracer);
final String branch = (String) this.settings.getSetting(ScopeSettings.SCOPE_BRANCH);
Statistics.INSTANCE.registerBranch(branch);
final boolean mustSetGlobalTracer = (boolean) this.settings.getSetting(ScopeSettings.SCOPE_TRACER_GLOBAL);
final boolean isAutoInstrument = (boolean) this.settings.getSetting(ScopeSettings.SCOPE_INSTRUMENTATION_ENABLED);
try {
final boolean mustInstrumentForRunner = ScopeRunnerFilter.INSTANCE.mustApplyRunner(this.settings);
Statistics.INSTANCE.registerRunnerActivation(mustInstrumentForRunner);
if(mustInstrumentForRunner) {
final boolean runnerRegistered = ScopeGlobalRunner.registerIfAbsent(ScopeRunnerImplFactory.INSTANCE.create(this.remoteSettings));
if (!runnerRegistered) {
LOG.warn("Scope Runner could not be registered as ScopeGlobalRunner. Registered runner as Global: " + ScopeGlobalRunner.get());
} else {
for(final ScopeRunnerAgentRule rule : this.runnerAgentRulesResolver.resolve()) {
LOG.debug("--- Installed " + rule);
rule.installOn(this.instrumentation);
}
}
}
} catch (final IllegalArgumentException e) {
Statistics.INSTANCE.registerRunnerActivation(false);
LOG.error(e.getMessage());
}
final boolean mustInstrumentForCoverage = (boolean) this.settings.getSetting(ScopeSettings.SCOPE_CODE_PATH_ENABLED);
Statistics.INSTANCE.registerCoverageActivation(mustInstrumentForCoverage);
if (mustInstrumentForCoverage) {
final boolean coverageReporterRegistered = GlobalCoverageReporter.registerIfAbsent(CoverageReporterImplFactory.INSTANCE.create(this.settings));
if (!coverageReporterRegistered) {
LOG.warn("Scope CoverageReporter could not be registered as GlobalCoverageReporter. Registered reporter as Global: " + GlobalCoverageReporter.get());
} else {
this.coverageInstrumentation.installOn(this.instrumentation);
for (final ScopeCoverageAgentRule rule : this.coverageAgentRulesResolver.resolve()) {
LOG.debug("--- Installed " + rule);
rule.installOn(this.instrumentation);
}
}
}
if (mustSetGlobalTracer) {
if (!this.tracerRegisterAsGlobalTracer.registerAsGlobalTracer(this.tracer)) {
LOG.warn("ScopeTracer could not be registered as GlobalTracer. Registered tracer as Global: " + GlobalTracer.get());
}
}
if (isAutoInstrument) {
for (final Initializer initializer : this.initializersResolver.resolve()) {
LOG.debug("--- Executed " + initializer);
initializer.run();
}
for (final ScopeAgentRule rule : this.agentRulesResolver.resolve()) {
LOG.debug("--- Installed " + rule);
rule.installOn(this.instrumentation);
}
}
return this.tracer;
}
private static void checkLoadedByBootstrapClassloader(Class clazz) {
if (clazz.getClassLoader() != null) {
throw new RuntimeException(clazz.getName() + " must be loaded by bootstrap classloader");
}
}
public static void agentmain(String arg, Instrumentation instrumentation) throws Exception {
premain(arg, instrumentation);
}
}