diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java index 932f8fb60c3..028965e4296 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java @@ -177,6 +177,7 @@ public boolean isEnabledByDefault() { private static boolean llmObsAgentlessEnabled = false; private static boolean usmEnabled = false; private static boolean telemetryEnabled = true; + private static boolean flareEnabled = true; private static boolean dynamicInstrumentationEnabled = false; private static boolean exceptionReplayEnabled = false; private static boolean codeOriginEnabled = false; @@ -205,6 +206,7 @@ public static void start( // these default services are not used during native-image builds remoteConfigEnabled = false; telemetryEnabled = false; + flareEnabled = false; // apply trace instrumentation, but skip other products at native-image build time startDatadogAgent(initTelemetry, inst); StaticEventLogger.end("Agent.start"); @@ -485,6 +487,10 @@ public static void shutdown(final boolean sync) { if (telemetryEnabled) { stopTelemetry(); } + if (flareEnabled) { + stopFlarePoller(); + } + if (agentlessLogSubmissionEnabled) { shutdownLogsIntake(); } @@ -641,6 +647,9 @@ public void execute() { if (telemetryEnabled) { startTelemetry(instrumentation, scoClass, sco); } + if (flareEnabled) { + startFlarePoller(scoClass, sco); + } } private void resumeRemoteComponents() { @@ -1106,6 +1115,34 @@ private static void stopTelemetry() { } } + private static void startFlarePoller(Class scoClass, Object sco) { + StaticEventLogger.begin("Flare Poller"); + try { + final Class tracerFlarePollerClass = + AGENT_CLASSLOADER.loadClass("datadog.flare.TracerFlarePoller"); + final Method tracerFlarePollerStartMethod = + tracerFlarePollerClass.getMethod("start", scoClass); + tracerFlarePollerStartMethod.invoke(null, sco); + } catch (final Throwable e) { + log.warn("Unable start Flare Poller", e); + } + StaticEventLogger.end("Flare Poller"); + } + + private static void stopFlarePoller() { + if (AGENT_CLASSLOADER == null) { + return; + } + try { + final Class tracerFlarePollerClass = + AGENT_CLASSLOADER.loadClass("datadog.flare.TracerFlarePoller"); + final Method tracerFlarePollerStopMethod = tracerFlarePollerClass.getMethod("stop"); + tracerFlarePollerStopMethod.invoke(null); + } catch (final Throwable ex) { + log.warn("Error encountered while stopping Flare Poller", ex); + } + } + private static void initializeDelayedCrashTracking() { initializeCrashTracking(true, isCrashTrackingAutoconfigEnabled()); } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/TracerInstaller.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/TracerInstaller.java index 6bd27c31bb1..27ef91c423b 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/TracerInstaller.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/TracerInstaller.java @@ -21,7 +21,7 @@ public static synchronized void installGlobalTracer( CoreTracer.builder() .sharedCommunicationObjects(sharedCommunicationObjects) .profilingContextIntegration(profilingContextIntegration) - .pollForTracerFlareRequests() + .reportInTracerFlare() .pollForTracingConfiguration() .build(); installGlobalTracer(tracer); diff --git a/dd-java-agent/build.gradle b/dd-java-agent/build.gradle index 891e58fc79c..fad4f6d6cc4 100644 --- a/dd-java-agent/build.gradle +++ b/dd-java-agent/build.gradle @@ -294,6 +294,10 @@ dependencies { // do not bring along slf4j and dependent subprojects // (which are loaded on the bootstrap cl) } + + sharedShadowInclude project(':utils:flare-utils'), { + transitive = false + } sharedShadowInclude libs.bundles.cafe.crypto sharedShadowInclude project(':remote-config:remote-config-api'), { transitive = false diff --git a/dd-trace-core/build.gradle b/dd-trace-core/build.gradle index d415949e629..0141e7377f1 100644 --- a/dd-trace-core/build.gradle +++ b/dd-trace-core/build.gradle @@ -36,7 +36,6 @@ excludedClassesCoverage += [ 'datadog.trace.common.writer.TraceProcessingWorker.NonDaemonTraceSerializingHandler', // Interface with an empty defender method 'datadog.trace.core.propagation.HttpCodec.Extractor', - 'datadog.trace.core.flare.*', 'datadog.trace.llmobs.writer.ddintake.LLMObsSpanMapper', 'datadog.trace.llmobs.writer.ddintake.LLMObsSpanMapper.PayloadV1', // FIXME(DSM): test coverage needed diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 5f64f71cbf1..5184a72d6da 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -85,7 +85,6 @@ import datadog.trace.core.baggage.BaggagePropagator; import datadog.trace.core.datastreams.DataStreamsMonitoring; import datadog.trace.core.datastreams.DefaultDataStreamsMonitoring; -import datadog.trace.core.flare.TracerFlarePoller; import datadog.trace.core.histogram.Histograms; import datadog.trace.core.monitor.HealthMetrics; import datadog.trace.core.monitor.MonitoringImpl; @@ -131,7 +130,7 @@ * datadog.trace.api.Tracer and TracerAPI, it coordinates many functions necessary creating, * reporting, and propagating traces */ -public class CoreTracer implements AgentTracer.TracerAPI { +public class CoreTracer implements AgentTracer.TracerAPI, TracerFlare.Reporter { private static final Logger log = LoggerFactory.getLogger(CoreTracer.class); // UINT64 max value public static final BigInteger TRACE_ID_MAX = @@ -165,8 +164,6 @@ public static CoreTracerBuilder builder() { /** Nanosecond offset to counter clock drift */ private volatile long counterDrift; - private final TracerFlarePoller tracerFlarePoller; - private final TracingConfigPoller tracingConfigPoller; private final PendingTraceBuffer pendingTraceBuffer; @@ -328,7 +325,7 @@ public static class CoreTracerBuilder { private DataStreamsMonitoring dataStreamsMonitoring; private ProfilingContextIntegration profilingContextIntegration = ProfilingContextIntegration.NoOp.INSTANCE; - private boolean pollForTracerFlareRequests; + private boolean reportInTracerFlare; private boolean pollForTracingConfiguration; private boolean injectBaggageAsTags; private boolean flushOnClose; @@ -455,8 +452,8 @@ public CoreTracerBuilder profilingContextIntegration( return this; } - public CoreTracerBuilder pollForTracerFlareRequests() { - this.pollForTracerFlareRequests = true; + public CoreTracerBuilder reportInTracerFlare() { + this.reportInTracerFlare = true; return this; } @@ -534,7 +531,7 @@ public CoreTracer build() { timeSource, dataStreamsMonitoring, profilingContextIntegration, - pollForTracerFlareRequests, + reportInTracerFlare, pollForTracingConfiguration, injectBaggageAsTags, flushOnClose); @@ -566,7 +563,7 @@ private CoreTracer( final TimeSource timeSource, final DataStreamsMonitoring dataStreamsMonitoring, final ProfilingContextIntegration profilingContextIntegration, - final boolean pollForTracerFlareRequests, + final boolean reportInTracerFlare, final boolean pollForTracingConfiguration, final boolean injectBaggageAsTags, final boolean flushOnClose) { @@ -594,7 +591,7 @@ private CoreTracer( timeSource, dataStreamsMonitoring, profilingContextIntegration, - pollForTracerFlareRequests, + reportInTracerFlare, pollForTracingConfiguration, injectBaggageAsTags, flushOnClose); @@ -625,7 +622,7 @@ private CoreTracer( final TimeSource timeSource, final DataStreamsMonitoring dataStreamsMonitoring, final ProfilingContextIntegration profilingContextIntegration, - final boolean pollForTracerFlareRequests, + final boolean reportInTracerFlare, final boolean pollForTracingConfiguration, final boolean injectBaggageAsTags, final boolean flushOnClose) { @@ -636,6 +633,9 @@ private CoreTracer( assert taggedHeaders != null; assert baggageMapping != null; + if (reportInTracerFlare) { + TracerFlare.addReporter(this); + } this.timeSource = timeSource == null ? SystemTimeSource.INSTANCE : timeSource; startTimeNano = this.timeSource.getCurrentTimeNanos(); startNanoTicks = this.timeSource.getNanoTicks(); @@ -740,11 +740,6 @@ private CoreTracer( sharedCommunicationObjects.monitoring = monitoring; sharedCommunicationObjects.createRemaining(config); - tracerFlarePoller = new TracerFlarePoller(dynamicConfig); - if (pollForTracerFlareRequests) { - tracerFlarePoller.start(config, sharedCommunicationObjects, this); - } - tracingConfigPoller = new TracingConfigPoller(dynamicConfig); if (pollForTracingConfiguration) { tracingConfigPoller.start(config, sharedCommunicationObjects); @@ -1288,7 +1283,6 @@ public void close() { metricsAggregator.close(); dataStreamsMonitoring.close(); externalAgentLauncher.close(); - tracerFlarePoller.stop(); healthMetrics.close(); } @@ -1342,7 +1336,9 @@ public TraceSegment getTraceSegment() { return null; } - public void addTracerReportToFlare(ZipOutputStream zip) throws IOException { + @Override + public void addReportToFlare(ZipOutputStream zip) throws IOException { + TracerFlare.addText(zip, "dynamic_config.txt", dynamicConfig.toString()); TracerFlare.addText(zip, "tracer_health.txt", healthMetrics.summary()); TracerFlare.addText(zip, "span_metrics.txt", SpanMetricRegistry.getInstance().summary()); } diff --git a/settings.gradle.kts b/settings.gradle.kts index 0db78b03163..085a179155a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -142,6 +142,7 @@ include( ":dd-java-agent:testing", ":utils:config-utils", ":utils:container-utils", + ":utils:flare-utils", ":utils:socket-utils", ":utils:test-agent-utils:decoder", ":utils:test-utils", diff --git a/utils/flare-utils/build.gradle.kts b/utils/flare-utils/build.gradle.kts new file mode 100644 index 00000000000..f718826c226 --- /dev/null +++ b/utils/flare-utils/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("java-library") +} + +apply(from = "$rootDir/gradle/java.gradle") + +dependencies { + api(libs.okhttp) + api(libs.moshi) + + compileOnly(project(":communication")) + implementation(project(":utils:version-utils")) + implementation(project(":internal-api")) + implementation(libs.slf4j) +} diff --git a/dd-trace-core/src/main/java/datadog/trace/core/flare/TracerFlarePoller.java b/utils/flare-utils/src/main/java/datadog/flare/TracerFlarePoller.java similarity index 89% rename from dd-trace-core/src/main/java/datadog/trace/core/flare/TracerFlarePoller.java rename to utils/flare-utils/src/main/java/datadog/flare/TracerFlarePoller.java index 3142c476f0e..e37d714fb9f 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/flare/TracerFlarePoller.java +++ b/utils/flare-utils/src/main/java/datadog/flare/TracerFlarePoller.java @@ -1,4 +1,4 @@ -package datadog.trace.core.flare; +package datadog.flare; import com.squareup.moshi.Json; import com.squareup.moshi.JsonAdapter; @@ -10,8 +10,6 @@ import datadog.remoteconfig.state.ConfigKey; import datadog.remoteconfig.state.ProductListener; import datadog.trace.api.Config; -import datadog.trace.api.DynamicConfig; -import datadog.trace.core.CoreTracer; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; @@ -20,7 +18,6 @@ public final class TracerFlarePoller { private static final String FLARE_LOG_LEVEL = "flare-log-level"; - private final DynamicConfig dynamicConfig; private Runnable stopPreparer; private Runnable stopSubmitter; @@ -28,20 +25,29 @@ public final class TracerFlarePoller { private TracerFlareService tracerFlareService; private final Map configAction = new HashMap<>(); + private static TracerFlarePoller INSTANCE; - public TracerFlarePoller(DynamicConfig dynamicConfig) { - this.dynamicConfig = dynamicConfig; + public static void start(SharedCommunicationObjects sco) { + if (null == INSTANCE) { + INSTANCE = new TracerFlarePoller(); + } + INSTANCE.doStart(sco); } - public void start(Config config, SharedCommunicationObjects sco, CoreTracer tracer) { + public static void stop() { + if (null != INSTANCE) { + INSTANCE.doStop(); + } + } + + private void doStart(SharedCommunicationObjects sco) { + Config config = Config.get(); stopPreparer = new Preparer().register(config, sco); stopSubmitter = new Submitter().register(config, sco); - - tracerFlareService = - new TracerFlareService(config, dynamicConfig, sco.okHttpClient, sco.agentUrl, tracer); + tracerFlareService = new TracerFlareService(config, sco.okHttpClient, sco.agentUrl); } - public void stop() { + private void doStop() { if (null != stopPreparer) { stopPreparer.run(); } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/flare/TracerFlareService.java b/utils/flare-utils/src/main/java/datadog/flare/TracerFlareService.java similarity index 93% rename from dd-trace-core/src/main/java/datadog/trace/core/flare/TracerFlareService.java rename to utils/flare-utils/src/main/java/datadog/flare/TracerFlareService.java index 7b64f1fe1c2..dcb097287a3 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/flare/TracerFlareService.java +++ b/utils/flare-utils/src/main/java/datadog/flare/TracerFlareService.java @@ -1,14 +1,12 @@ -package datadog.trace.core.flare; +package datadog.flare; +import static datadog.common.version.VersionInfo.VERSION; import static datadog.trace.util.AgentThreadFactory.AgentThread.TRACER_FLARE; import datadog.communication.http.OkHttpUtils; import datadog.trace.api.Config; -import datadog.trace.api.DynamicConfig; import datadog.trace.api.flare.TracerFlare; import datadog.trace.api.time.TimeUtils; -import datadog.trace.core.CoreTracer; -import datadog.trace.core.DDTraceCoreInfo; import datadog.trace.logging.GlobalLogLevelSwitcher; import datadog.trace.logging.LogLevel; import datadog.trace.util.AgentTaskScheduler; @@ -54,27 +52,18 @@ final class TracerFlareService { private final AgentTaskScheduler scheduler = new AgentTaskScheduler(TRACER_FLARE); private final Config config; - private final DynamicConfig dynamicConfig; private final OkHttpClient okHttpClient; private final HttpUrl flareUrl; - private final CoreTracer tracer; private boolean logLevelOverridden; private volatile long flareStartMillis; private Scheduled scheduledCleanup; - TracerFlareService( - Config config, - DynamicConfig dynamicConfig, - OkHttpClient okHttpClient, - HttpUrl agentUrl, - CoreTracer tracer) { + TracerFlareService(Config config, OkHttpClient okHttpClient, HttpUrl agentUrl) { this.config = config; - this.dynamicConfig = dynamicConfig; this.okHttpClient = okHttpClient; this.flareUrl = agentUrl.newBuilder().addPathSegments(FLARE_ENDPOINT).build(); - this.tracer = tracer; applyTriageReportTrigger(config.getTriageReportTrigger()); } @@ -213,7 +202,6 @@ private byte[] buildFlareZip(long startMillis, long endMillis, boolean dumpThrea addPrelude(zip, startMillis, endMillis); addConfig(zip); addRuntime(zip); - tracer.addTracerReportToFlare(zip); TracerFlare.addReportsToFlare(zip); if (dumpThreads) { addThreadDump(zip); @@ -227,12 +215,11 @@ private byte[] buildFlareZip(long startMillis, long endMillis, boolean dumpThrea private void addPrelude(ZipOutputStream zip, long startMillis, long endMillis) throws IOException { TracerFlare.addText(zip, "flare_info.txt", flareInfo(startMillis, endMillis)); - TracerFlare.addText(zip, "tracer_version.txt", DDTraceCoreInfo.VERSION); + TracerFlare.addText(zip, "tracer_version.txt", VERSION); } private void addConfig(ZipOutputStream zip) throws IOException { TracerFlare.addText(zip, "initial_config.txt", config.toString()); - TracerFlare.addText(zip, "dynamic_config.txt", dynamicConfig.toString()); } private void addRuntime(ZipOutputStream zip) throws IOException {