diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/log/AgentlessLogSubmission.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/log/AgentlessLogSubmission.java new file mode 100644 index 00000000000..303d1455a4d --- /dev/null +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/log/AgentlessLogSubmission.java @@ -0,0 +1,147 @@ +package datadog.trace.bootstrap.instrumentation.log; + +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.traceConfig; + +import datadog.trace.api.Config; +import datadog.trace.api.CorrelationIdentifier; +import datadog.trace.api.logging.intake.LogsIntake; +import datadog.trace.bootstrap.instrumentation.api.Tags; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * Submits events captured by logging backend instrumentations to the agentless logs intake. + * + *

Events use the payload shape of Log4j's JSON layout, which the logs backend already parses. + * Callers must capture events on the producer thread, so that the correlation identifiers match the + * active span. + */ +public final class AgentlessLogSubmission { + + public static final String TRACE = "TRACE"; + public static final String DEBUG = "DEBUG"; + public static final String INFO = "INFO"; + public static final String WARN = "WARN"; + public static final String ERROR = "ERROR"; + public static final String FATAL = "FATAL"; + + private static final int MAX_STACKTRACE_STRING_LENGTH = 16 * 1_024; + + private static final int SUBMISSION_SEVERITY = + severity(Config.get().getAgentlessLogSubmissionLevel()); + + private AgentlessLogSubmission() {} + + /** Returns whether events of the given level reach the configured submission level. */ + public static boolean isLevelEnabled(String level) { + return severity(level) >= SUBMISSION_SEVERITY; + } + + /** Converts a {@link java.util.logging.Level} integer value to a level name of this class. */ + public static String julLevel(int value) { + if (value >= 1100) { + return FATAL; + } else if (value >= 1000) { + return ERROR; + } else if (value >= 900) { + return WARN; + } else if (value >= 800) { + return INFO; + } else if (value >= 500) { + return DEBUG; + } + return TRACE; + } + + /** + * Submits an event. + * + * @param level a level name of this class + * @param context the user context of the event, such as the MDC, or {@code null} + */ + public static void submit( + String thread, + String level, + String loggerName, + String message, + Throwable thrown, + long timestamp, + Map context) { + Map log = new HashMap<>(); + log.put("thread", thread); + log.put("level", level); + log.put("loggerName", loggerName); + log.put("message", message); + log.put("timestamp", timestamp); + if (thrown != null) { + log.put("thrown", thrown(thrown)); + } + Map contextMap = new HashMap<>(); + if (traceConfig().isLogsInjectionEnabled()) { + addCorrelationValues(contextMap); + } + if (context != null) { + contextMap.putAll(context); + } + log.put("contextMap", contextMap); + LogsIntake.log(log); + } + + private static Map thrown(Throwable thrown) { + Map thrownLog = new HashMap<>(); + thrownLog.put("message", thrown.getMessage()); + thrownLog.put("name", thrown.getClass().getCanonicalName()); + StringWriter stringWriter = new StringWriter(); + thrown.printStackTrace(new PrintWriter(stringWriter)); + StringBuffer stackTrace = stringWriter.getBuffer(); + thrownLog.put( + "extendedStackTrace", + stackTrace.substring(0, Math.min(stackTrace.length(), MAX_STACKTRACE_STRING_LENGTH))); + return thrownLog; + } + + private static void addCorrelationValues(Map context) { + Config config = Config.get(); + putIfNotEmpty(context, Tags.DD_SERVICE, config.getServiceName()); + putIfNotEmpty(context, Tags.DD_ENV, config.getEnv()); + putIfNotEmpty(context, Tags.DD_VERSION, config.getVersion()); + String traceId = CorrelationIdentifier.getTraceId(); + if (traceId != null && !traceId.equals("0")) { + context.put(CorrelationIdentifier.getTraceIdKey(), traceId); + } + String spanId = CorrelationIdentifier.getSpanId(); + if (spanId != null && !spanId.equals("0")) { + context.put(CorrelationIdentifier.getSpanIdKey(), spanId); + } + } + + private static void putIfNotEmpty(Map context, String key, String value) { + if (value != null && !value.isEmpty()) { + context.put(key, value); + } + } + + static int severity(String level) { + switch (level == null ? INFO : level.toUpperCase(Locale.ROOT)) { + case "ALL": + return 0; + case TRACE: + return 1; + case DEBUG: + return 2; + case WARN: + return 4; + case ERROR: + return 5; + case FATAL: + return 6; + case "OFF": + return 7; + default: + return 3; + } + } +} diff --git a/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/log/AgentlessLogSubmissionTest.java b/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/log/AgentlessLogSubmissionTest.java new file mode 100644 index 00000000000..8355972846d --- /dev/null +++ b/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/log/AgentlessLogSubmissionTest.java @@ -0,0 +1,122 @@ +package datadog.trace.bootstrap.instrumentation.log; + +import static datadog.trace.bootstrap.instrumentation.log.AgentlessLogSubmission.isLevelEnabled; +import static datadog.trace.bootstrap.instrumentation.log.AgentlessLogSubmission.julLevel; +import static datadog.trace.bootstrap.instrumentation.log.AgentlessLogSubmission.severity; +import static datadog.trace.bootstrap.instrumentation.log.AgentlessLogSubmission.submit; +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import datadog.trace.api.logging.intake.LogsIntake; +import datadog.trace.api.logging.intake.LogsWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.tabletest.junit.TableTest; + +class AgentlessLogSubmissionTest { + + private final List> messages = new ArrayList<>(); + + @BeforeEach + void registerWriter() { + LogsIntake.registerWriter( + new LogsWriter() { + @Override + public void log(Map message) { + messages.add(message); + } + + @Override + public void start() {} + + @Override + public void shutdown() {} + }); + } + + @AfterEach + void unregisterWriter() { + LogsIntake.registerWriter(null); + } + + @TableTest({ + "scenario | value | level", + "OFF | 2000 | FATAL", + "JBoss FATAL | 1100 | FATAL", + "SEVERE | 1000 | ERROR", + "WARNING | 900 | WARN ", + "INFO | 800 | INFO ", + "CONFIG | 700 | DEBUG", + "FINE | 500 | DEBUG", + "FINER | 400 | TRACE", + "FINEST | 300 | TRACE" + }) + void mapsJulLevels(int value, String level) { + assertEquals(level, julLevel(value)); + } + + @TableTest({ + "scenario | lower | higher", + "ALL and TRACE | ALL | TRACE ", + "TRACE, DEBUG | trace | DEBUG ", + "DEBUG, INFO | DEBUG | INFO ", + "INFO, WARN | INFO | WARN ", + "WARN, ERROR | WARN | ERROR ", + "ERROR, FATAL | ERROR | FATAL ", + "FATAL, OFF | FATAL | OFF " + }) + void ordersLevels(String lower, String higher) { + assertTrue(severity(lower) < severity(higher)); + } + + @Test + void defaultsToInfo() { + assertFalse(isLevelEnabled("DEBUG")); + assertTrue(isLevelEnabled("INFO")); + assertTrue(isLevelEnabled("unknown")); + } + + @Test + void submitsEvent() { + submit( + "main", + "ERROR", + "logger", + "message", + new IllegalStateException("failure"), + 42L, + singletonMap("custom", "value")); + + assertEquals(1, messages.size()); + Map message = messages.get(0); + assertEquals("main", message.get("thread")); + assertEquals("ERROR", message.get("level")); + assertEquals("logger", message.get("loggerName")); + assertEquals("message", message.get("message")); + assertEquals(42L, message.get("timestamp")); + assertEquals(singletonMap("custom", "value"), message.get("contextMap")); + Map thrown = (Map) message.get("thrown"); + assertEquals(IllegalStateException.class.getName(), thrown.get("name")); + assertEquals("failure", thrown.get("message")); + assertTrue( + thrown + .get("extendedStackTrace") + .toString() + .startsWith("java.lang.IllegalStateException: failure")); + } + + @Test + void submitsEventWithoutOptionalFields() { + submit("main", "INFO", "logger", "message", null, 42L, null); + + assertEquals(1, messages.size()); + assertFalse(messages.get(0).containsKey("thrown")); + assertTrue(((Map) messages.get(0).get("contextMap")).isEmpty()); + } +} diff --git a/dd-java-agent/agent-logs-intake/src/main/java/datadog/trace/logging/intake/LogsWriterImpl.java b/dd-java-agent/agent-logs-intake/src/main/java/datadog/trace/logging/intake/LogsWriterImpl.java index 6d88d0e0a59..d4f6544bda9 100644 --- a/dd-java-agent/agent-logs-intake/src/main/java/datadog/trace/logging/intake/LogsWriterImpl.java +++ b/dd-java-agent/agent-logs-intake/src/main/java/datadog/trace/logging/intake/LogsWriterImpl.java @@ -89,14 +89,16 @@ public void log(Map message) { } private void logPollingLoop() { - BackendApi backendApi = apiFactory.createBackendApi(intake); - LogsDispatcher logsDispatcher = new LogsDispatcher(backendApi); + LogsDispatcher logsDispatcher = null; while (!Thread.currentThread().isInterrupted()) { try { List> batch = new ArrayList<>(); batch.add(messageQueue.take()); messageQueue.drainTo(batch); + if (logsDispatcher == null) { + logsDispatcher = createDispatcher(); + } logsDispatcher.dispatch(batch); } catch (InterruptedException e) { @@ -107,7 +109,19 @@ private void logPollingLoop() { List> batch = new ArrayList<>(); messageQueue.drainTo(batch); if (!batch.isEmpty()) { + if (logsDispatcher == null) { + logsDispatcher = createDispatcher(); + } logsDispatcher.dispatch(batch); } } + + /** + * Creating the HTTP client initializes TLS, which can initialize the JUL {@code LogManager}. It + * is created for the first log, after the application has configured its own log manager. + */ + private LogsDispatcher createDispatcher() { + BackendApi backendApi = apiFactory.createBackendApi(intake); + return new LogsDispatcher(backendApi); + } } diff --git a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/build.gradle b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/build.gradle index 8a6ac89d6ce..45203a1f4d7 100644 --- a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/build.gradle +++ b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/build.gradle @@ -11,6 +11,22 @@ muzzle { } } +addTestSuiteForDir('latestDepTest', 'test') +addTestSuiteExtendingForDir('latestDepForkedTest', 'latestDepTest', 'test') + +["latestDepTest", "latestDepForkedTest"].each { + tasks.named(it, Test) { + testJvmConstraints { + // jboss-logmanager 3.2 requires Java 17 + minJavaVersion = JavaVersion.VERSION_17 + } + } +} + dependencies { compileOnly group: 'org.jboss.logmanager', name: 'jboss-logmanager', version: '1.1.0.GA' + + // LoggerNode.publish(ExtLogRecord), used by the instrumentation, was introduced in 1.2.0.GA + testImplementation group: 'org.jboss.logmanager', name: 'jboss-logmanager', version: '1.2.0.GA' + latestDepTestImplementation group: 'org.jboss.logmanager', name: 'jboss-logmanager', version: '+' } diff --git a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/gradle.lockfile b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/gradle.lockfile index 3c939ee397c..ab3738e57ff 100644 --- a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/gradle.lockfile +++ b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/gradle.lockfile @@ -2,63 +2,71 @@ # Manual edits can break the build and are not advised. # This file is expected to be part of source control. # To regenerate this file, run: ./gradlew :dd-java-agent:instrumentation:jboss:jboss-logmanager-1.1:dependencies --write-locks -cafe.cryptography:curve25519-elisabeth:0.1.0=testRuntimeClasspath -cafe.cryptography:ed25519-elisabeth:0.1.0=testRuntimeClasspath -ch.qos.logback:logback-classic:1.2.13=testCompileClasspath,testRuntimeClasspath -ch.qos.logback:logback-core:1.2.13=testCompileClasspath,testRuntimeClasspath -com.blogspot.mydailyjava:weak-lock-free:0.17=buildTimeInstrumentationPlugin,compileClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq.okhttp3:okhttp:3.12.15=testCompileClasspath,testRuntimeClasspath -com.datadoghq.okio:okio:1.17.6=testCompileClasspath,testRuntimeClasspath -com.datadoghq:dd-instrument-java:0.0.6=buildTimeInstrumentationPlugin,compileClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:dd-javac-plugin-client:0.2.2=buildTimeInstrumentationPlugin,compileClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:java-dogstatsd-client:4.4.5=testRuntimeClasspath -com.datadoghq:sketches-java:0.8.3=testRuntimeClasspath +cafe.cryptography:curve25519-elisabeth:0.1.0=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +cafe.cryptography:ed25519-elisabeth:0.1.0=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +ch.qos.logback:logback-classic:1.2.13=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +ch.qos.logback:logback-core:1.2.13=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.blogspot.mydailyjava:weak-lock-free:0.17=buildTimeInstrumentationPlugin,compileClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okhttp3:okhttp:3.12.15=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okio:okio:1.17.6=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:dd-instrument-java:0.0.6=buildTimeInstrumentationPlugin,compileClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:dd-javac-plugin-client:0.2.2=buildTimeInstrumentationPlugin,compileClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:java-dogstatsd-client:4.4.5=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.datadoghq:sketches-java:0.8.3=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath com.github.javaparser:javaparser-core:3.25.6=codenarc -com.github.jnr:jffi:1.3.15=testRuntimeClasspath -com.github.jnr:jnr-a64asm:1.0.0=testRuntimeClasspath -com.github.jnr:jnr-constants:0.10.4=testRuntimeClasspath -com.github.jnr:jnr-enxio:0.32.20=testRuntimeClasspath -com.github.jnr:jnr-ffi:2.2.19=testRuntimeClasspath -com.github.jnr:jnr-posix:3.1.22=testRuntimeClasspath -com.github.jnr:jnr-unixsocket:0.38.25=testRuntimeClasspath -com.github.jnr:jnr-x86asm:1.0.2=testRuntimeClasspath +com.github.jnr:jffi:1.3.15=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-a64asm:1.0.0=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-constants:0.10.4=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-enxio:0.32.20=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-ffi:2.2.19=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-posix:3.1.22=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-unixsocket:0.38.25=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-x86asm:1.0.2=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath com.github.spotbugs:spotbugs-annotations:4.10.4=compileClasspath,spotbugs com.github.spotbugs:spotbugs:4.10.4=spotbugs com.github.stephenc.jcip:jcip-annotations:1.0-1=spotbugs -com.google.auto.service:auto-service-annotations:1.1.1=annotationProcessor,compileClasspath,testAnnotationProcessor,testCompileClasspath -com.google.auto.service:auto-service:1.1.1=annotationProcessor,testAnnotationProcessor -com.google.auto:auto-common:1.2.1=annotationProcessor,testAnnotationProcessor -com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath +com.google.auto.service:auto-service-annotations:1.1.1=annotationProcessor,compileClasspath,latestDepForkedTestAnnotationProcessor,latestDepForkedTestCompileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,testAnnotationProcessor,testCompileClasspath +com.google.auto.service:auto-service:1.1.1=annotationProcessor,latestDepForkedTestAnnotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.auto:auto-common:1.2.1=annotationProcessor,latestDepForkedTestAnnotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,latestDepForkedTestAnnotationProcessor,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath com.google.code.gson:gson:2.14.0=spotbugs -com.google.errorprone:error_prone_annotations:2.18.0=annotationProcessor,testAnnotationProcessor -com.google.errorprone:error_prone_annotations:2.47.0=testCompileClasspath,testRuntimeClasspath +com.google.errorprone:error_prone_annotations:2.18.0=annotationProcessor,latestDepForkedTestAnnotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.errorprone:error_prone_annotations:2.47.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.google.errorprone:error_prone_annotations:2.48.0=spotbugs -com.google.guava:failureaccess:1.0.1=annotationProcessor,testAnnotationProcessor -com.google.guava:failureaccess:1.0.3=testCompileClasspath,testRuntimeClasspath -com.google.guava:guava:32.0.1-jre=annotationProcessor,testAnnotationProcessor -com.google.guava:guava:33.6.0-jre=testCompileClasspath,testRuntimeClasspath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.google.j2objc:j2objc-annotations:2.8=annotationProcessor,testAnnotationProcessor -com.google.j2objc:j2objc-annotations:3.1=testCompileClasspath,testRuntimeClasspath -com.google.re2j:re2j:1.8=testRuntimeClasspath -com.squareup.moshi:moshi:1.11.0=testCompileClasspath,testRuntimeClasspath -com.squareup.okhttp3:logging-interceptor:3.12.12=testCompileClasspath,testRuntimeClasspath -com.squareup.okhttp3:okhttp:3.12.12=testCompileClasspath,testRuntimeClasspath -com.squareup.okio:okio:1.17.5=testCompileClasspath,testRuntimeClasspath +com.google.guava:failureaccess:1.0.1=annotationProcessor,latestDepForkedTestAnnotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:failureaccess:1.0.3=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.guava:guava:32.0.1-jre=annotationProcessor,latestDepForkedTestAnnotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:guava:33.6.0-jre=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,latestDepForkedTestAnnotationProcessor,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath +com.google.j2objc:j2objc-annotations:2.8=annotationProcessor,latestDepForkedTestAnnotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.j2objc:j2objc-annotations:3.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.re2j:re2j:1.8=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +com.squareup.moshi:moshi:1.11.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:logging-interceptor:3.12.12=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:okhttp:3.12.12=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okio:okio:1.17.5=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.thoughtworks.qdox:qdox:1.12.1=codenarc -commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testRuntimeClasspath -commons-io:commons-io:2.11.0=testCompileClasspath,testRuntimeClasspath +commons-fileupload:commons-fileupload:1.5=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +commons-io:commons-io:2.11.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath commons-io:commons-io:2.21.0=spotbugs -de.thetaphi:forbiddenapis:3.11=compileClasspath,testCompileClasspath,testRuntimeClasspath -io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath -io.sqreen:libsqreen:17.5.0=testRuntimeClasspath -javax.servlet:javax.servlet-api:3.1.0=testCompileClasspath,testRuntimeClasspath +de.thetaphi:forbiddenapis:3.11=compileClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +io.leangen.geantyref:geantyref:1.3.16=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +io.smallrye.common:smallrye-common-constraint:2.15.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.smallrye.common:smallrye-common-cpu:2.15.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.smallrye.common:smallrye-common-expression:2.15.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.smallrye.common:smallrye-common-function:2.15.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.smallrye.common:smallrye-common-net:2.15.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.smallrye.common:smallrye-common-os:2.15.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.smallrye.common:smallrye-common-ref:2.15.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.sqreen:libsqreen:17.5.0=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +jakarta.json:jakarta.json-api:2.1.3=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +javax.servlet:javax.servlet-api:3.1.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath jaxen:jaxen:2.0.6=spotbugs -junit:junit:4.13.2=testRuntimeClasspath -net.bytebuddy:byte-buddy-agent:1.18.12=buildTimeInstrumentationPlugin,compileClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -net.bytebuddy:byte-buddy:1.18.12=buildTimeInstrumentationPlugin,compileClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -net.java.dev.jna:jna-platform:5.8.0=testRuntimeClasspath -net.java.dev.jna:jna:5.8.0=testRuntimeClasspath +junit:junit:4.13.2=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.18.12=buildTimeInstrumentationPlugin,compileClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy:1.18.12=buildTimeInstrumentationPlugin,compileClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.java.dev.jna:jna-platform:5.8.0=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +net.java.dev.jna:jna:5.8.0=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath net.sf.saxon:Saxon-HE:12.10=spotbugs org.apache.ant:ant-antlr:1.10.14=codenarc org.apache.ant:ant-junit:1.10.14=codenarc @@ -67,59 +75,64 @@ org.apache.commons:commons-lang3:3.20.0=spotbugs org.apache.commons:commons-text:1.15.0=spotbugs org.apache.logging.log4j:log4j-api:2.26.1=spotbugs org.apache.logging.log4j:log4j-core:2.26.1=spotbugs -org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath -org.checkerframework:checker-qual:3.33.0=annotationProcessor,testAnnotationProcessor +org.apiguardian:apiguardian-api:1.1.2=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.checkerframework:checker-qual:3.33.0=annotationProcessor,latestDepForkedTestAnnotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor org.codehaus.groovy:groovy-ant:3.0.23=codenarc org.codehaus.groovy:groovy-docgenerator:3.0.23=codenarc org.codehaus.groovy:groovy-groovydoc:3.0.23=codenarc org.codehaus.groovy:groovy-json:3.0.23=codenarc -org.codehaus.groovy:groovy-json:3.0.25=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-json:3.0.25=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.codehaus.groovy:groovy-templates:3.0.23=codenarc org.codehaus.groovy:groovy-xml:3.0.23=codenarc org.codehaus.groovy:groovy:3.0.23=codenarc -org.codehaus.groovy:groovy:3.0.25=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy:3.0.25=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.codenarc:CodeNarc:3.7.0=codenarc org.dom4j:dom4j:2.2.0=spotbugs +org.eclipse.parsson:parsson:1.1.7=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath org.gmetrics:GMetrics:2.1.0=codenarc -org.hamcrest:hamcrest-core:1.3=testRuntimeClasspath -org.hamcrest:hamcrest:3.0=testCompileClasspath,testRuntimeClasspath +org.hamcrest:hamcrest-core:1.3=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.hamcrest:hamcrest:3.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jboss.logging:jboss-logging:3.6.2.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath org.jboss.logmanager:jboss-logmanager:1.1.0.GA=compileClasspath -org.jctools:jctools-core-jdk11:4.0.6=testRuntimeClasspath -org.jctools:jctools-core:4.0.6=testRuntimeClasspath -org.jspecify:jspecify:1.0.0=testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath -org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter:5.14.1=testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-commons:1.14.1=testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-engine:1.14.1=testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-launcher:1.14.1=testRuntimeClasspath -org.junit.platform:junit-platform-runner:1.14.1=testRuntimeClasspath -org.junit.platform:junit-platform-suite-api:1.14.1=testRuntimeClasspath -org.junit.platform:junit-platform-suite-commons:1.14.1=testRuntimeClasspath -org.junit:junit-bom:5.14.1=testCompileClasspath,testRuntimeClasspath -org.mockito:mockito-core:4.4.0=testRuntimeClasspath -org.objenesis:objenesis:3.3=testCompileClasspath,testRuntimeClasspath -org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath +org.jboss.logmanager:jboss-logmanager:1.2.0.GA=testCompileClasspath,testRuntimeClasspath +org.jboss.logmanager:jboss-logmanager:3.2.2.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.jboss.modules:jboss-modules:2.3.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.jctools:jctools-core-jdk11:4.0.6=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.jctools:jctools-core:4.0.6=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.jspecify:jspecify:1.0.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-api:5.14.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.14.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-params:5.14.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter:5.14.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-commons:1.14.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-engine:1.14.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.14.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-runner:1.14.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.14.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-suite-commons:1.14.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit:junit-bom:5.14.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-core:4.4.0=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.objenesis:objenesis:3.3=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.opentest4j:opentest4j:1.3.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.ow2.asm:asm-analysis:9.10.1=spotbugs -org.ow2.asm:asm-analysis:9.7.1=testRuntimeClasspath -org.ow2.asm:asm-commons:9.10.1=spotbugs,testRuntimeClasspath -org.ow2.asm:asm-tree:9.10.1=spotbugs,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.7.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-commons:9.10.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,spotbugs,testRuntimeClasspath +org.ow2.asm:asm-tree:9.10.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,spotbugs,testRuntimeClasspath org.ow2.asm:asm-util:9.10.1=spotbugs -org.ow2.asm:asm-util:9.7.1=testRuntimeClasspath -org.ow2.asm:asm:9.10.1=buildTimeInstrumentationPlugin,compileClasspath,muzzleTooling,runtimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath -org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath -org.slf4j:jul-to-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath -org.slf4j:log4j-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath +org.ow2.asm:asm-util:9.7.1=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.ow2.asm:asm:9.10.1=buildTimeInstrumentationPlugin,compileClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath +org.slf4j:jcl-over-slf4j:1.7.30=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:jul-to-slf4j:1.7.30=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:log4j-over-slf4j:1.7.30=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.slf4j:slf4j-api:1.7.30=buildTimeInstrumentationPlugin,compileClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath -org.slf4j:slf4j-api:1.7.32=testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.32=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.slf4j:slf4j-api:2.0.17=spotbugsSlf4j org.slf4j:slf4j-api:2.0.18=spotbugs org.slf4j:slf4j-simple:2.0.17=spotbugsSlf4j -org.snakeyaml:snakeyaml-engine:2.9=buildTimeInstrumentationPlugin,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.spockframework:spock-bom:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath -org.spockframework:spock-core:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath -org.tabletest:tabletest-junit:1.2.2=testCompileClasspath,testRuntimeClasspath -org.tabletest:tabletest-parser:1.2.1=testCompileClasspath,testRuntimeClasspath +org.snakeyaml:snakeyaml-engine:2.9=buildTimeInstrumentationPlugin,latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.spockframework:spock-bom:2.4-groovy-3.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.spockframework:spock-core:2.4-groovy-3.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.tabletest:tabletest-junit:1.2.2=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.tabletest:tabletest-parser:1.2.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.xmlresolver:xmlresolver:5.3.3=spotbugs empty=spotbugsPlugins diff --git a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/main/java/datadog/trace/instrumentation/jbosslogmanager/ExtLogRecordInstrumentation.java b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/main/java/datadog/trace/instrumentation/jbosslogmanager/ExtLogRecordInstrumentation.java index 982c26a34bd..d98e9f2a5f5 100644 --- a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/main/java/datadog/trace/instrumentation/jbosslogmanager/ExtLogRecordInstrumentation.java +++ b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/main/java/datadog/trace/instrumentation/jbosslogmanager/ExtLogRecordInstrumentation.java @@ -28,7 +28,7 @@ import org.jboss.logmanager.ExtLogRecord; @AutoService(InstrumenterModule.class) -public class ExtLogRecordInstrumentation extends InstrumenterModule.Tracing +public class ExtLogRecordInstrumentation extends InstrumenterModule.ContextTracking implements Instrumenter.ForTypeHierarchy, Instrumenter.HasMethodAdvice { public ExtLogRecordInstrumentation() { super("jboss-logmanager"); diff --git a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/main/java/datadog/trace/instrumentation/jbosslogmanager/LoggerNodeInstrumentation.java b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/main/java/datadog/trace/instrumentation/jbosslogmanager/LoggerNodeInstrumentation.java index 4e8cc81ef37..74d1801c24c 100644 --- a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/main/java/datadog/trace/instrumentation/jbosslogmanager/LoggerNodeInstrumentation.java +++ b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/main/java/datadog/trace/instrumentation/jbosslogmanager/LoggerNodeInstrumentation.java @@ -10,16 +10,19 @@ import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.InstrumenterConfig; import datadog.trace.bootstrap.CallDepthThreadLocalMap; import datadog.trace.bootstrap.InstrumentationContext; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; +import datadog.trace.bootstrap.instrumentation.log.AgentlessLogSubmission; import java.util.Map; import net.bytebuddy.asm.Advice; import org.jboss.logmanager.ExtLogRecord; +import org.jboss.logmanager.MDC; @AutoService(InstrumenterModule.class) -public class LoggerNodeInstrumentation extends InstrumenterModule.Tracing +public class LoggerNodeInstrumentation extends InstrumenterModule.ContextTracking implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { public LoggerNodeInstrumentation() { super("jboss-logmanager"); @@ -42,6 +45,13 @@ public void methodAdvice(MethodTransformer transformer) { .and(named("publish")) .and(takesArgument(0, named("org.jboss.logmanager.ExtLogRecord"))), LoggerNodeInstrumentation.class.getName() + "$AttachContextAdvice"); + if (InstrumenterConfig.get().isAgentlessLogSubmissionEnabled()) { + transformer.applyAdvice( + isMethod() + .and(named("publish")) + .and(takesArgument(0, named("org.jboss.logmanager.ExtLogRecord"))), + LoggerNodeInstrumentation.class.getName() + "$SubmitLogAdvice"); + } } public static class AttachContextAdvice { @@ -69,4 +79,35 @@ public static void resetDepth(@Advice.Enter boolean shouldReset) { } } } + + public static class SubmitLogAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static boolean submit(@Advice.Argument(0) ExtLogRecord record) { + if (CallDepthThreadLocalMap.incrementCallDepth(AgentlessLogSubmission.class) > 0) { + return false; + } + try { + String level = AgentlessLogSubmission.julLevel(record.getLevel().intValue()); + if (AgentlessLogSubmission.isLevelEnabled(level)) { + AgentlessLogSubmission.submit( + record.getThreadName(), + level, + record.getLoggerName(), + record.getFormattedMessage(), + record.getThrown(), + record.getMillis(), + MDC.copy()); + } + } catch (Throwable ignored) { + } + return true; + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void resetDepth(@Advice.Enter boolean shouldReset) { + if (shouldReset) { + CallDepthThreadLocalMap.reset(AgentlessLogSubmission.class); + } + } + } } diff --git a/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/test/java/JBossLogsIntakeForkedTest.java b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/test/java/JBossLogsIntakeForkedTest.java new file mode 100644 index 00000000000..1c147b6c10d --- /dev/null +++ b/dd-java-agent/instrumentation/jboss/jboss-logmanager-1.1/src/test/java/JBossLogsIntakeForkedTest.java @@ -0,0 +1,306 @@ +import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_ENABLED; +import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_LEVEL; +import static datadog.trace.api.config.GeneralConfig.ENV; +import static datadog.trace.api.config.GeneralConfig.SERVICE_NAME; +import static datadog.trace.api.config.GeneralConfig.VERSION; +import static datadog.trace.api.config.TraceInstrumentationConfig.LOGS_INJECTION_ENABLED; +import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_ENABLED; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import datadog.context.ContextScope; +import datadog.trace.agent.test.AbstractInstrumentationTest; +import datadog.trace.api.Config; +import datadog.trace.api.CorrelationIdentifier; +import datadog.trace.api.InstrumenterConfig; +import datadog.trace.api.logging.intake.LogsIntake; +import datadog.trace.api.logging.intake.LogsWriter; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.bootstrap.instrumentation.api.Tags; +import datadog.trace.test.junit.utils.config.WithConfig; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.stream.Collectors; +import org.jboss.logmanager.ExtLogRecord; +import org.jboss.logmanager.Level; +import org.jboss.logmanager.LogContext; +import org.jboss.logmanager.Logger; +import org.jboss.logmanager.MDC; +import org.jboss.logmanager.handlers.AsyncHandler; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Each subclass runs in its own JVM with the agent installed for its configuration. */ +@WithConfig(key = AGENTLESS_LOG_SUBMISSION_ENABLED, value = "true") +@WithConfig(key = LOGS_INJECTION_ENABLED, value = "true") +@WithConfig(key = AGENTLESS_LOG_SUBMISSION_LEVEL, value = "WARN") +@WithConfig(key = SERVICE_NAME, value = "jboss-service") +@WithConfig(key = ENV, value = "jboss-env") +@WithConfig(key = VERSION, value = "1.0") +abstract class AbstractJBossLogsIntakeForkedTest extends AbstractInstrumentationTest { + static final String LOGGER_NAME = "test.jboss.intake"; + static final List> MESSAGES = new CopyOnWriteArrayList<>(); + // The JBoss LogManager is not the JUL log manager of the test JVM + static final LogContext LOG_CONTEXT = LogContext.create(); + + final Logger parent = LOG_CONTEXT.getLogger(LOGGER_NAME); + final Logger logger = LOG_CONTEXT.getLogger(LOGGER_NAME + ".child"); + final ContextHandler handler = new ContextHandler(); + + @BeforeAll + static void registerWriter() { + LogsIntake.registerWriter(new CapturingLogsWriter()); + } + + @AfterAll + static void unregisterWriter() { + LogsIntake.registerWriter(null); + } + + @BeforeEach + void setupLoggers() { + MESSAGES.clear(); + MDC.clear(); + parent.setUseParentHandlers(false); + parent.setLevel(Level.TRACE); + logger.setLevel(Level.TRACE); + logger.addHandler(handler); + } + + @AfterEach + void cleanupLoggers() { + MDC.clear(); + logger.removeHandler(handler); + parent.clearHandlers(); + } + + static boolean agentless() { + return InstrumenterConfig.get().isAgentlessLogSubmissionEnabled(); + } + + static boolean injection() { + return Config.get().isLogsInjectionEnabled(); + } + + static Map serviceTags() { + Map tags = new HashMap<>(); + if (injection()) { + tags.put(Tags.DD_SERVICE, "jboss-service"); + tags.put(Tags.DD_ENV, "jboss-env"); + tags.put(Tags.DD_VERSION, "1.0"); + } + return tags; + } + + @Test + void submitsFilteredEventsWithMappedLevelsAndExceptions() { + logger.log(Level.DEBUG, "debug"); + logger.log(Level.INFO, "info"); + logger.log(Level.WARN, "warn"); + logger.log(java.util.logging.Level.WARNING, "jul {0}", "warning"); + logger.log(Level.ERROR, "error", new IllegalStateException("failure")); + logger.log(Level.FATAL, "fatal"); + + assertEquals(6, handler.contexts.size()); + if (!agentless()) { + assertTrue(MESSAGES.isEmpty()); + return; + } + assertEquals(asList("warn", "jul warning", "error", "fatal"), values("message")); + assertEquals(asList("WARN", "WARN", "ERROR", "FATAL"), values("level")); + for (Map message : MESSAGES) { + assertEquals(logger.getName(), message.get("loggerName")); + assertEquals(Thread.currentThread().getName(), message.get("thread")); + assertInstanceOf(Long.class, message.get("timestamp")); + } + Map thrown = (Map) MESSAGES.get(2).get("thrown"); + assertEquals(IllegalStateException.class.getName(), thrown.get("name")); + assertEquals("failure", thrown.get("message")); + assertTrue( + thrown.get("extendedStackTrace").toString().contains("IllegalStateException: failure")); + assertFalse(MESSAGES.get(0).containsKey("thrown")); + } + + @Test + void submitsProducerContextAndPreservesUserMdc() { + AgentSpan span = AgentTracer.startSpan("test", "jboss-producer"); + String traceId; + String spanId; + String childSpanId; + try (ContextScope scope = AgentTracer.activateSpan(span)) { + traceId = CorrelationIdentifier.getTraceId(); + spanId = CorrelationIdentifier.getSpanId(); + MDC.put("custom", "value"); + logger.log(Level.WARN, "active"); + AgentSpan child = AgentTracer.startSpan("test", "jboss-child"); + try (ContextScope childScope = AgentTracer.activateSpan(child)) { + childSpanId = CorrelationIdentifier.getSpanId(); + logger.log(Level.WARN, "child"); + } finally { + child.finish(); + } + MDC.put("dd.trace_id", "user-trace"); + logger.log(Level.WARN, "collision"); + MDC.clear(); + } finally { + span.finish(); + } + logger.log(Level.WARN, "outside"); + + Map active = handler.contexts.get(0); + assertEquals(injection() ? traceId : null, active.get("dd.trace_id")); + assertEquals(injection() ? spanId : null, active.get("dd.span_id")); + assertEquals("value", active.get("custom")); + if (!agentless()) { + assertTrue(MESSAGES.isEmpty()); + return; + } + assertEquals(asList("active", "child", "collision", "outside"), values("message")); + Map expected = serviceTags(); + if (injection()) { + expected.put("dd.trace_id", traceId); + expected.put("dd.span_id", spanId); + } + expected.put("custom", "value"); + assertEquals(expected, contextMap(0)); + assertEquals(injection() ? traceId : null, contextMap(1).get("dd.trace_id")); + assertEquals(injection() ? childSpanId : null, contextMap(1).get("dd.span_id")); + assertEquals("user-trace", contextMap(2).get("dd.trace_id")); + assertEquals(serviceTags(), contextMap(3)); + } + + @Test + void submitsOnceWhenTheEventReachesParentHandlers() { + ContextHandler parentHandler = new ContextHandler(); + parent.addHandler(parentHandler); + + logger.log(Level.WARN, "propagated"); + + assertEquals(1, handler.contexts.size()); + assertEquals(1, parentHandler.contexts.size()); + assertEquals(agentless() ? singletonList("propagated") : emptyList(), values("message")); + } + + @Test + void submitsOnceWithProducerContextWhenDeliveryIsAsynchronous() throws Exception { + CountDownLatch release = new CountDownLatch(1); + CountDownLatch delivered = new CountDownLatch(1); + ContextHandler asyncTarget = + new ContextHandler() { + @Override + public void publish(LogRecord record) { + try { + release.await(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + super.publish(record); + delivered.countDown(); + } + }; + AsyncHandler async = new AsyncHandler(); + async.addHandler(asyncTarget); + logger.removeHandler(handler); + logger.addHandler(async); + try { + AgentSpan span = AgentTracer.startSpan("test", "jboss-async"); + String traceId; + String spanId; + try (ContextScope scope = AgentTracer.activateSpan(span)) { + traceId = CorrelationIdentifier.getTraceId(); + spanId = CorrelationIdentifier.getSpanId(); + logger.log(Level.WARN, "async"); + } finally { + span.finish(); + } + release.countDown(); + + assertTrue(delivered.await(5, TimeUnit.SECONDS)); + assertEquals(injection() ? spanId : null, asyncTarget.contexts.get(0).get("dd.span_id")); + if (agentless()) { + assertEquals(1, MESSAGES.size()); + assertEquals(injection() ? traceId : null, contextMap(0).get("dd.trace_id")); + assertEquals(injection() ? spanId : null, contextMap(0).get("dd.span_id")); + } else { + assertTrue(MESSAGES.isEmpty()); + } + } finally { + logger.removeHandler(async); + async.close(); + } + } + + static List values(String key) { + return MESSAGES.stream().map(message -> message.get(key)).collect(Collectors.toList()); + } + + static Map contextMap(int index) { + return (Map) MESSAGES.get(index).get("contextMap"); + } + + /** Records the correlation context seen by JBoss handlers. */ + static class ContextHandler extends Handler { + final List> contexts = new CopyOnWriteArrayList<>(); + + @Override + public void publish(LogRecord record) { + ExtLogRecord extRecord = (ExtLogRecord) record; + Map context = new HashMap<>(); + context.put("dd.trace_id", extRecord.getMdc("dd.trace_id")); + context.put("dd.span_id", extRecord.getMdc("dd.span_id")); + context.put("custom", extRecord.getMdc("custom")); + contexts.add(context); + } + + @Override + public void flush() {} + + @Override + public void close() {} + } + + static class CapturingLogsWriter implements LogsWriter { + @Override + public void log(Map message) { + if (message.get("loggerName").toString().startsWith(LOGGER_NAME)) { + MESSAGES.add(message); + } + } + + @Override + public void start() {} + + @Override + public void shutdown() {} + } +} + +class JBossLogsIntakeForkedTest extends AbstractJBossLogsIntakeForkedTest {} + +@WithConfig(key = AGENTLESS_LOG_SUBMISSION_ENABLED, value = "false") +class JBossNoSubmissionForkedTest extends AbstractJBossLogsIntakeForkedTest {} + +@WithConfig(key = LOGS_INJECTION_ENABLED, value = "false") +class JBossNoInjectionForkedTest extends AbstractJBossLogsIntakeForkedTest {} + +@WithConfig(key = TRACE_ENABLED, value = "false") +class JBossCiAgentlessForkedTest extends AbstractJBossLogsIntakeForkedTest {} + +@WithConfig(key = AGENTLESS_LOG_SUBMISSION_ENABLED, value = "false") +@WithConfig(key = TRACE_ENABLED, value = "false") +class JBossCiCorrelationForkedTest extends AbstractJBossLogsIntakeForkedTest {} diff --git a/dd-smoke-tests/log-injection/src/test/groovy/datadog/smoketest/LogInjectionSmokeTest.groovy b/dd-smoke-tests/log-injection/src/test/groovy/datadog/smoketest/LogInjectionSmokeTest.groovy index f6a65371ec5..33739de2775 100644 --- a/dd-smoke-tests/log-injection/src/test/groovy/datadog/smoketest/LogInjectionSmokeTest.groovy +++ b/dd-smoke-tests/log-injection/src/test/groovy/datadog/smoketest/LogInjectionSmokeTest.groovy @@ -32,7 +32,8 @@ abstract class LogInjectionSmokeTest extends AbstractSmokeTest { static final String LOG4J2_BACKEND = "Log4j2" static final String LOGBACK_BACKEND = "Logback" - static final Set DIRECT_LOG_SUBMISSION_BACKENDS = [LOG4J2_BACKEND, LOGBACK_BACKEND] as Set + static final String JBOSS_BACKEND = "JBoss" + static final Set DIRECT_LOG_SUBMISSION_BACKENDS = [LOG4J2_BACKEND, LOGBACK_BACKEND, JBOSS_BACKEND] as Set @Shared File outputLogFile @@ -514,7 +515,7 @@ class JULInterfaceLog4j2LatestBackend extends JULInterfaceLog4j2Backend {} class JULInterfaceJBossBackend extends LogInjectionSmokeTest { def backend() { - "JBoss" + JBOSS_BACKEND } def supportsJson() { false @@ -762,7 +763,7 @@ class Log4j2InterfaceSlf4jToLogbackLatestBackend extends Log4j2InterfaceSlf4jToL class JBossInterfaceJBossBackend extends LogInjectionSmokeTest { def backend() { - "JBoss" + JBOSS_BACKEND } def supportsJson() { false