diff --git a/internal-api/src/main/java/datadog/trace/api/telemetry/LogCollector.java b/internal-api/src/main/java/datadog/trace/api/telemetry/LogCollector.java index 80412572dd4..99ff6845574 100644 --- a/internal-api/src/main/java/datadog/trace/api/telemetry/LogCollector.java +++ b/internal-api/src/main/java/datadog/trace/api/telemetry/LogCollector.java @@ -12,6 +12,10 @@ import org.slf4j.Marker; import org.slf4j.MarkerFactory; +/** + * A collector for telemetry log messages. Most consumers should not use this class directly, but rather + * use SLF4J logging, which will call this collector automatically. + */ public class LogCollector { public static final Marker SEND_TELEMETRY = MarkerFactory.getMarker("SEND_TELEMETRY"); public static final Marker EXCLUDE_TELEMETRY = MarkerFactory.getMarker("EXCLUDE_TELEMETRY"); @@ -34,6 +38,12 @@ private LogCollector() { this.rawLogMessages = new ConcurrentHashMap<>(maxCapacity); } + /** + * Schedule a log message for processing by the telemetry subsystem. + * @param logLevel ERROR, WARN or DEBUG. Other values are accepted, but will be normalized to DEBUG. Cannot be null. + * @param message The log message, needs to be free from sensitive data. Cannot be null. + * @param throwable An optional throwable to associate a stacktrace with the log message, can be null. + */ public void addLogMessage(String logLevel, String message, Throwable throwable) { if (rawLogMessages.size() >= maxCapacity) { // TODO: We could emit a metric for dropped logs. @@ -69,6 +79,10 @@ public Collection drain() { return list; } + /** + * A log message scheduled for processing by the telemetry subsystem. + * Consumers should not use this class directly. + */ public static class RawLogMessage { public final String message; public final String logLevel; diff --git a/telemetry/src/main/java/datadog/telemetry/api/LogMessageLevel.java b/telemetry/src/main/java/datadog/telemetry/api/LogMessageLevel.java index 5cb9ae30c27..c572a6d148f 100644 --- a/telemetry/src/main/java/datadog/telemetry/api/LogMessageLevel.java +++ b/telemetry/src/main/java/datadog/telemetry/api/LogMessageLevel.java @@ -1,23 +1,21 @@ package datadog.telemetry.api; -import javax.annotation.Nullable; - public enum LogMessageLevel { ERROR, WARN, DEBUG; - @Nullable public static LogMessageLevel fromString(String value) { + if (value == null) { + return DEBUG; + } switch (value) { case "ERROR": return ERROR; case "WARN": return WARN; - case "DEBUG": - return DEBUG; default: - return null; + return DEBUG; } } } diff --git a/telemetry/src/main/java/datadog/telemetry/log/LogPeriodicAction.java b/telemetry/src/main/java/datadog/telemetry/log/LogPeriodicAction.java index c90b103f404..8f5316ba7ca 100644 --- a/telemetry/src/main/java/datadog/telemetry/log/LogPeriodicAction.java +++ b/telemetry/src/main/java/datadog/telemetry/log/LogPeriodicAction.java @@ -36,12 +36,9 @@ public void doIteration(TelemetryService service) { new LogMessage() .message(rawLogMsg.message) .tracerTime(rawLogMsg.timestamp) + .level(LogMessageLevel.fromString(rawLogMsg.logLevel)) .count(rawLogMsg.count); - if (rawLogMsg.logLevel != null) { - logMessage.level(LogMessageLevel.fromString(rawLogMsg.logLevel)); - } - if (rawLogMsg.throwable != null) { logMessage.stackTrace(renderStackTrace(rawLogMsg.throwable)); } diff --git a/telemetry/src/test/groovy/datadog/telemetry/log/LogPeriodicActionTest.groovy b/telemetry/src/test/groovy/datadog/telemetry/log/LogPeriodicActionTest.groovy index aa29acdd6a3..2cf8cf94727 100644 --- a/telemetry/src/test/groovy/datadog/telemetry/log/LogPeriodicActionTest.groovy +++ b/telemetry/src/test/groovy/datadog/telemetry/log/LogPeriodicActionTest.groovy @@ -21,6 +21,34 @@ class LogPeriodicActionTest extends DDSpecification { LogCollector.get().drain() } + void 'log with unknown log level is normalized to DEBUG'() { + LogMessage logMessage + + when: + LogCollector.get().addLogMessage("INFO", "test", null) + periodicAction.doIteration(telemetryService) + + then: + 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } + 0 * _ + logMessage.getLevel() == LogMessageLevel.DEBUG + logMessage.getMessage() == 'test' + } + + void 'log with null log level is normalized to DEBUG'() { + LogMessage logMessage + + when: + LogCollector.get().addLogMessage(null, "test", null) + periodicAction.doIteration(telemetryService) + + then: + 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } + 0 * _ + logMessage.getLevel() == LogMessageLevel.DEBUG + logMessage.getMessage() == 'test' + } + void 'log with datadog throwable'() { LogMessage logMessage @@ -34,6 +62,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getStackTrace() == "${MutableException.canonicalName}: exception\n" + " at datadog.MyClass.method(file:42)\n" @@ -52,6 +81,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getStackTrace() == "${MutableException.canonicalName}\n" + " at java.MyClass.method(file:42)\n" @@ -70,6 +100,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getStackTrace() == "${MutableException.canonicalName}\n" } @@ -85,6 +116,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getCount() == 2 } @@ -104,6 +136,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getStackTrace() != null logMessage.getCount() == 2 @@ -129,6 +162,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getStackTrace() == "${MutableException.canonicalName}\n" + " at (redacted)\n" + @@ -162,6 +196,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getStackTrace() == "${MutableException.canonicalName}\n" + " at (redacted)\n" + @@ -204,6 +239,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getStackTrace() == "${MutableException.canonicalName}\n" + " at java.MyClass.method(file:42)\n" + @@ -240,6 +276,7 @@ class LogPeriodicActionTest extends DDSpecification { then: 1 * telemetryService.addLogMessage(_) >> { args -> logMessage = args[0] } 0 * _ + logMessage.getLevel() == LogMessageLevel.ERROR logMessage.getMessage() == 'test' logMessage.getStackTrace() == "${MutableException.canonicalName}\n" + " at java.MyClass.method(file:42)\n" +