From 07b28a067f3989b8afcdec914fee4aff72c8998c Mon Sep 17 00:00:00 2001 From: Brian Marks Date: Fri, 13 Sep 2024 08:59:23 -0400 Subject: [PATCH 01/13] POC - log in JSON format --- .../logging/simplelogger/SLCompatHelper.java | 119 ++++++++++++++++-- .../datadog/trace/api/ConfigDefaults.java | 1 + .../trace/api/config/GeneralConfig.java | 1 + .../main/java/datadog/trace/api/Config.java | 12 ++ newfilehere | 0 5 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 newfilehere diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java index a8037c2fbdd..c0a3ce298cf 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java @@ -1,5 +1,6 @@ package datadog.trace.logging.simplelogger; +import datadog.trace.api.Config; import datadog.trace.logging.LogLevel; import datadog.trace.logging.LoggerHelper; import org.slf4j.Marker; @@ -34,7 +35,11 @@ public void log(LogLevel level, Marker marker, String message, Throwable t) { if (settings.showDateTime) { timeMillis = System.currentTimeMillis(); } - log(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); + if (Config.get().isJsonLogsEnabled()) { + logJson(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); + } else { + log(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); + } } void log( @@ -51,6 +56,83 @@ void log( log(level, marker, startTimeMillis, timeMillis, threadName, message, t); } + void logJson( + LogLevel level, + Marker marker, + long startTimeMillis, + long timeMillis, + String message, + Throwable t) { + String threadName = null; + if (settings.showThreadName) { + threadName = Thread.currentThread().getName(); + } + logJson(level, marker, startTimeMillis, timeMillis, threadName, message, t); + } + + void logJson( + LogLevel level, + Marker marker, + long startTimeMillis, + long timeMillis, + String threadName, + String message, + Throwable t) { + StringBuilder buf = new StringBuilder(32); + + buf.append("{"); + + if (timeMillis >= 0 && settings.showDateTime) { + embedJsonKey(buf, "time"); + settings.dateTimeFormatter.appendFormattedDate(buf, timeMillis, startTimeMillis); + buf.append("\","); + } + + if (settings.showThreadName && threadName != null) { + embedJson(buf, "threadName", threadName, true); + } + + embedJsonKey(buf, "level"); + if (settings.warnLevelString != null && level == LogLevel.WARN) { + embedJsonValue(buf, settings.warnLevelString, true); + } else if (marker != null) { + embedJsonValue(buf, marker.getName(), true); + } else { + embedJsonValue(buf, level.name(), true); + } + + if (!logName.isEmpty()) { + embedJson(buf, "logName", logName, true); + } + + if (t != null) { + embedExceptionJson(buf, t); + } + + embedJson(buf, "message", message, false); + + buf.append("}"); + + settings.printStream.println(buf); + } + + private void embedJson(StringBuilder buf, String key, String value, boolean withComma) { + embedJsonKey(buf, key); + embedJsonValue(buf, value, withComma); + } + + private void embedJsonKey(StringBuilder buf, String key) { + buf.append("\"").append(key).append("\":\""); + } + + private void embedJsonValue(StringBuilder buf, String value, boolean withComma) { + buf.append(value).append("\""); + + if (withComma) { + buf.append(","); + } + } + void log( LogLevel level, Marker marker, @@ -88,32 +170,43 @@ void log( } buf.append(' '); - if (logName.length() > 0) { + if (!logName.isEmpty()) { buf.append(logName).append(" - "); } buf.append(message); - if (settings.embedException) { + if (settings.embedException && t != null) { embedException(buf, t); } - settings.printStream.println(buf.toString()); + settings.printStream.println(buf); if (!settings.embedException && t != null) { t.printStackTrace(settings.printStream); } } private void embedException(StringBuilder buf, Throwable t) { - if (t != null) { - buf.append(" [exception:"); - buf.append(t.toString()); - buf.append("."); - for (StackTraceElement element : t.getStackTrace()) { - buf.append(" at "); - buf.append(element.toString()); - } - buf.append("]"); + buf.append(" [exception:"); + buf.append(t.toString()); + buf.append("."); + for (StackTraceElement element : t.getStackTrace()) { + buf.append(" at "); + buf.append(element.toString()); } + buf.append("]"); + } + + private void embedExceptionJson(StringBuilder buf, Throwable t) { + buf.append("\"exception\":{"); + embedJson(buf, "message", t.getMessage(), true); + buf.append("\"stackTrace\":[\""); + + for (StackTraceElement element : t.getStackTrace()) { + buf.append(element.toString()); + buf.append("\",\""); + } + + buf.append("\"]"); } } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index f4e3357f78b..c2520558386 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -43,6 +43,7 @@ public final class ConfigDefaults { public static final String DEFAULT_SERVLET_ROOT_CONTEXT_SERVICE_NAME = "root-servlet"; public static final String DEFAULT_AGENT_WRITER_TYPE = "DDAgentWriter"; public static final boolean DEFAULT_STARTUP_LOGS_ENABLED = true; + public static final boolean DEFAULT_JSON_LOGS_ENABLED = false; static final boolean DEFAULT_WRITER_BAGGAGE_INJECT = true; static final String DEFAULT_SITE = "datadoghq.com"; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java index ee4886e7ad0..6323eee0390 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java @@ -36,6 +36,7 @@ public final class GeneralConfig { public static final String TRIAGE_REPORT_DIR = "triage.report.dir"; public static final String STARTUP_LOGS_ENABLED = "trace.startup.logs"; + public static final String JSON_LOGS_ENABLED = "trace.experimental.json.logs"; public static final String DOGSTATSD_START_DELAY = "dogstatsd.start-delay"; public static final String DOGSTATSD_HOST = "dogstatsd.host"; diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 0842b1af76a..99257a9eaad 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -89,6 +89,7 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_JMX_FETCH_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_LIMIT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_JSON_LOGS_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_LOGS_INJECTION_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_PARTIAL_FLUSH_MIN_SPANS; import static datadog.trace.api.ConfigDefaults.DEFAULT_PERF_METRICS_ENABLED; @@ -267,6 +268,7 @@ import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_ENABLED; import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_STATSD_HOST; import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_STATSD_PORT; +import static datadog.trace.api.config.GeneralConfig.JSON_LOGS_ENABLED; import static datadog.trace.api.config.GeneralConfig.LOG_LEVEL; import static datadog.trace.api.config.GeneralConfig.PERF_METRICS_ENABLED; import static datadog.trace.api.config.GeneralConfig.PRIMARY_TAG; @@ -599,12 +601,14 @@ public static String getHostName() { private final String runtimeVersion; private final String applicationKey; + /** * Note: this has effect only on profiling site. Traces are sent to Datadog agent and are not * affected by this setting. If CI Visibility is used with agentless mode, api key is used when * sending data (including traces) to backend */ private final String apiKey; + /** * Note: this has effect only on profiling site. Traces are sent to Datadog agent and are not * affected by this setting. @@ -932,6 +936,7 @@ public static String getHostName() { private final String triageReportDir; private final boolean startupLogsEnabled; + private final boolean jsonLogsEnabled; private final String configFileStatus; private final IdGenerationStrategy idGenerationStrategy; @@ -2104,6 +2109,7 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) startupLogsEnabled = configProvider.getBoolean(STARTUP_LOGS_ENABLED, DEFAULT_STARTUP_LOGS_ENABLED); + jsonLogsEnabled = configProvider.getBoolean(JSON_LOGS_ENABLED, DEFAULT_JSON_LOGS_ENABLED); cwsEnabled = configProvider.getBoolean(CWS_ENABLED, DEFAULT_CWS_ENABLED); cwsTlsRefresh = configProvider.getInteger(CWS_TLS_REFRESH, DEFAULT_CWS_TLS_REFRESH); @@ -3553,6 +3559,10 @@ public boolean isStartupLogsEnabled() { return startupLogsEnabled; } + public boolean isJsonLogsEnabled() { + return jsonLogsEnabled; + } + public boolean isCwsEnabled() { return cwsEnabled; } @@ -4744,6 +4754,8 @@ public String toString() { + triageReportDir + ", startLogsEnabled=" + startupLogsEnabled + + ", jsonLogsEnabled=" + + jsonLogsEnabled + ", configFile='" + configFileStatus + '\'' diff --git a/newfilehere b/newfilehere new file mode 100644 index 00000000000..e69de29bb2d From 10f5803db4a165ce4924832e3bab0ec3a6b7502b Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Tue, 12 Nov 2024 16:21:46 +0100 Subject: [PATCH 02/13] initial commit --- .../java/datadog/trace/bootstrap/Agent.java | 4 + .../logging/simplelogger/SLCompatHelper.java | 173 +++++++++--------- .../simplelogger/SLCompatSettings.java | 11 ++ .../datadog/trace/api/ConfigDefaults.java | 1 - .../trace/api/config/GeneralConfig.java | 1 - .../main/java/datadog/trace/api/Config.java | 10 - 6 files changed, 105 insertions(+), 95 deletions(-) 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 d5a990d4ac8..a5c1b65f08c 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 @@ -69,6 +69,8 @@ public class Agent { private static final String SIMPLE_LOGGER_SHOW_DATE_TIME_PROPERTY = "datadog.slf4j.simpleLogger.showDateTime"; + private static final String SIMPLE_LOGGER_JSON_ENABLED_PROPERTY = + "datadog.slf4j.simpleLogger.json.enabled"; private static final String SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY = "datadog.slf4j.simpleLogger.dateTimeFormat"; private static final String SIMPLE_LOGGER_DATE_TIME_FORMAT_DEFAULT = @@ -1104,6 +1106,8 @@ private static void configureLogger() { setSystemPropertyDefault(SIMPLE_LOGGER_SHOW_DATE_TIME_PROPERTY, "true"); setSystemPropertyDefault( SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY, SIMPLE_LOGGER_DATE_TIME_FORMAT_DEFAULT); + setSystemPropertyDefault( + SIMPLE_LOGGER_JSON_ENABLED_PROPERTY, "false"); String logLevel; if (isDebugMode()) { diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java index c0a3ce298cf..6884e67925f 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java @@ -1,6 +1,6 @@ package datadog.trace.logging.simplelogger; -import datadog.trace.api.Config; +import static datadog.trace.util.Strings.escapeToJson; import datadog.trace.logging.LogLevel; import datadog.trace.logging.LoggerHelper; import org.slf4j.Marker; @@ -35,10 +35,11 @@ public void log(LogLevel level, Marker marker, String message, Throwable t) { if (settings.showDateTime) { timeMillis = System.currentTimeMillis(); } - if (Config.get().isJsonLogsEnabled()) { - logJson(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); + + if (settings.jsonEnabled) { + logJson(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); } else { - log(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); + log(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); } } @@ -56,6 +57,70 @@ void log( log(level, marker, startTimeMillis, timeMillis, threadName, message, t); } + void log( + LogLevel level, + Marker marker, + long startTimeMillis, + long timeMillis, + String threadName, + String message, + Throwable t) { + StringBuilder buf = new StringBuilder(32); + + if (timeMillis >= 0 && settings.showDateTime) { + settings.dateTimeFormatter.appendFormattedDate(buf, timeMillis, startTimeMillis); + buf.append(' '); + } + + if (settings.showThreadName && threadName != null) { + buf.append('['); + buf.append(threadName); + buf.append("] "); + } + + if (settings.levelInBrackets) { + buf.append('['); + } + + if (settings.warnLevelString != null && level == LogLevel.WARN) { + buf.append(settings.warnLevelString); + } else if (marker != null) { + buf.append(marker.getName()); + } else { + buf.append(level.name()); + } + if (settings.levelInBrackets) { + buf.append(']'); + } + buf.append(' '); + + if (!logName.isEmpty()) { + buf.append(logName).append(" - "); + } + + buf.append(message); + + if (settings.embedException && t != null) { + embedException(buf, t); + } + + settings.printStream.println(buf); + if (!settings.embedException && t != null) { + t.printStackTrace(settings.printStream); + } + } + + private void embedException(StringBuilder buf, Throwable t) { + buf.append(" [exception:"); + buf.append(t.toString()); + buf.append("."); + for (StackTraceElement element : t.getStackTrace()) { + buf.append(" at "); + buf.append(element.toString()); + } + buf.append("]"); + } + void logJson( LogLevel level, Marker marker, @@ -81,7 +146,7 @@ void logJson( StringBuilder buf = new StringBuilder(32); buf.append("{"); - + if (timeMillis >= 0 && settings.showDateTime) { embedJsonKey(buf, "time"); settings.dateTimeFormatter.appendFormattedDate(buf, timeMillis, startTimeMillis); @@ -102,15 +167,15 @@ void logJson( } if (!logName.isEmpty()) { - embedJson(buf, "logName", logName, true); + embedJson(buf, "loggerName", logName, true); } + embedJson(buf, "message", message, false); if (t != null) { + buf.append(","); embedExceptionJson(buf, t); } - embedJson(buf, "message", message, false); - buf.append("}"); settings.printStream.println(buf); @@ -119,94 +184,36 @@ void logJson( private void embedJson(StringBuilder buf, String key, String value, boolean withComma) { embedJsonKey(buf, key); embedJsonValue(buf, value, withComma); + } private void embedJsonKey(StringBuilder buf, String key) { - buf.append("\"").append(key).append("\":\""); + buf.append("\"").append(escapeToJson(key)).append("\":\""); } private void embedJsonValue(StringBuilder buf, String value, boolean withComma) { - buf.append(value).append("\""); - + buf.append(escapeToJson(value)).append("\""); if (withComma) { buf.append(","); } } - - void log( - LogLevel level, - Marker marker, - long startTimeMillis, - long timeMillis, - String threadName, - String message, - Throwable t) { - StringBuilder buf = new StringBuilder(32); - - if (timeMillis >= 0 && settings.showDateTime) { - settings.dateTimeFormatter.appendFormattedDate(buf, timeMillis, startTimeMillis); - buf.append(' '); - } - - if (settings.showThreadName && threadName != null) { - buf.append('['); - buf.append(threadName); - buf.append("] "); - } - - if (settings.levelInBrackets) { - buf.append('['); - } - - if (settings.warnLevelString != null && level == LogLevel.WARN) { - buf.append(settings.warnLevelString); - } else if (marker != null) { - buf.append(marker.getName()); - } else { - buf.append(level.name()); - } - if (settings.levelInBrackets) { - buf.append(']'); - } - buf.append(' '); - - if (!logName.isEmpty()) { - buf.append(logName).append(" - "); - } - - buf.append(message); - - if (settings.embedException && t != null) { - embedException(buf, t); - } - - settings.printStream.println(buf); - if (!settings.embedException && t != null) { - t.printStackTrace(settings.printStream); - } - } - - private void embedException(StringBuilder buf, Throwable t) { - buf.append(" [exception:"); - buf.append(t.toString()); - buf.append("."); - for (StackTraceElement element : t.getStackTrace()) { - buf.append(" at "); - buf.append(element.toString()); - } - buf.append("]"); - } - private void embedExceptionJson(StringBuilder buf, Throwable t) { buf.append("\"exception\":{"); - embedJson(buf, "message", t.getMessage(), true); - buf.append("\"stackTrace\":[\""); - - for (StackTraceElement element : t.getStackTrace()) { - buf.append(element.toString()); - buf.append("\",\""); + embedJson(buf, "message",escapeToJson(t.getMessage()), true); + int length = t.getStackTrace().length; + if (length > 0) { + buf.append("\"stackTrace\":[\""); + int count = 0; + for (StackTraceElement element : t.getStackTrace()) { + count += 1; + buf.append(escapeToJson(element.toString())); + if (count != length) { + buf.append("\",\""); + } + } + buf.append("\"]"); } - buf.append("\"]"); + buf.append("}"); } } diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java index 955943fd6e9..a9e82dcdd42 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java @@ -1,5 +1,7 @@ package datadog.trace.logging.simplelogger; +import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; + import datadog.trace.logging.LogLevel; import datadog.trace.logging.LogReporter; import datadog.trace.logging.PrintStreamWrapper; @@ -33,9 +35,11 @@ public static final class Names { public static final String SHOW_THREAD_NAME = "showThreadName"; public static final String DATE_TIME_FORMAT = "dateTimeFormat"; public static final String SHOW_DATE_TIME = "showDateTime"; + public static final String JSON_ENABLED = "json.enabled"; public static final String DEFAULT_LOG_LEVEL = "defaultLogLevel"; public static final String EMBED_EXCEPTION = "embedException"; public static final String CONFIGURATION_FILE = "configurationFile"; + } public static final class Keys { @@ -53,6 +57,7 @@ public static final class Keys { public static final String SHOW_THREAD_NAME = PREFIX + Names.SHOW_THREAD_NAME; public static final String DATE_TIME_FORMAT = PREFIX + Names.DATE_TIME_FORMAT; public static final String SHOW_DATE_TIME = PREFIX + Names.SHOW_DATE_TIME; + public static final String JSON_ENABLED = PREFIX + Names.JSON_ENABLED; public static final String DEFAULT_LOG_LEVEL = PREFIX + Names.DEFAULT_LOG_LEVEL; public static final String EMBED_EXCEPTION = PREFIX + Names.EMBED_EXCEPTION; @@ -70,6 +75,7 @@ public static final class Defaults { public static final boolean SHOW_THREAD_NAME = true; public static final String DATE_TIME_FORMAT = null; public static final boolean SHOW_DATE_TIME = false; + public static final boolean JSON_ENABLED = false; public static final String DEFAULT_LOG_LEVEL = "INFO"; public static final boolean EMBED_EXCEPTION = false; @@ -271,6 +277,7 @@ static boolean getBoolean( final boolean showThreadName; final DTFormatter dateTimeFormatter; final boolean showDateTime; + final boolean jsonEnabled; final LogLevel defaultLogLevel; final boolean embedException; @@ -304,6 +311,7 @@ public SLCompatSettings( getString( properties, fileProperties, Keys.DATE_TIME_FORMAT, Defaults.DATE_TIME_FORMAT)), getBoolean(properties, fileProperties, Keys.SHOW_DATE_TIME, Defaults.SHOW_DATE_TIME), + getBoolean(properties, fileProperties, Keys.JSON_ENABLED, Defaults.JSON_ENABLED), LogLevel.fromString( getString( properties, fileProperties, Keys.DEFAULT_LOG_LEVEL, Defaults.DEFAULT_LOG_LEVEL)), @@ -321,6 +329,7 @@ public SLCompatSettings( boolean showThreadName, DTFormatter dateTimeFormatter, boolean showDateTime, + boolean jsonEnabled, LogLevel defaultLogLevel, boolean embedException) { this.properties = properties; @@ -333,6 +342,7 @@ public SLCompatSettings( this.showThreadName = showThreadName; this.dateTimeFormatter = dateTimeFormatter; this.showDateTime = showDateTime; + this.jsonEnabled = jsonEnabled; this.defaultLogLevel = defaultLogLevel; this.embedException = embedException; } @@ -375,6 +385,7 @@ public Map getSettingsDescription() { settingsDescription.put(Names.SHOW_SHORT_LOG_NAME, showShortLogName); settingsDescription.put(Names.SHOW_THREAD_NAME, showThreadName); settingsDescription.put(Names.SHOW_DATE_TIME, showDateTime); + settingsDescription.put(Names.JSON_ENABLED, jsonEnabled); String dateTimeFormat = getString(properties, fileProperties, Keys.DATE_TIME_FORMAT, Defaults.DATE_TIME_FORMAT); settingsDescription.put( diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index c2520558386..f4e3357f78b 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -43,7 +43,6 @@ public final class ConfigDefaults { public static final String DEFAULT_SERVLET_ROOT_CONTEXT_SERVICE_NAME = "root-servlet"; public static final String DEFAULT_AGENT_WRITER_TYPE = "DDAgentWriter"; public static final boolean DEFAULT_STARTUP_LOGS_ENABLED = true; - public static final boolean DEFAULT_JSON_LOGS_ENABLED = false; static final boolean DEFAULT_WRITER_BAGGAGE_INJECT = true; static final String DEFAULT_SITE = "datadoghq.com"; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java index 6323eee0390..ee4886e7ad0 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java @@ -36,7 +36,6 @@ public final class GeneralConfig { public static final String TRIAGE_REPORT_DIR = "triage.report.dir"; public static final String STARTUP_LOGS_ENABLED = "trace.startup.logs"; - public static final String JSON_LOGS_ENABLED = "trace.experimental.json.logs"; public static final String DOGSTATSD_START_DELAY = "dogstatsd.start-delay"; public static final String DOGSTATSD_HOST = "dogstatsd.host"; diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 99257a9eaad..aaea2e81227 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -89,7 +89,6 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_JMX_FETCH_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_LIMIT; -import static datadog.trace.api.ConfigDefaults.DEFAULT_JSON_LOGS_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_LOGS_INJECTION_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_PARTIAL_FLUSH_MIN_SPANS; import static datadog.trace.api.ConfigDefaults.DEFAULT_PERF_METRICS_ENABLED; @@ -268,7 +267,6 @@ import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_ENABLED; import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_STATSD_HOST; import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_STATSD_PORT; -import static datadog.trace.api.config.GeneralConfig.JSON_LOGS_ENABLED; import static datadog.trace.api.config.GeneralConfig.LOG_LEVEL; import static datadog.trace.api.config.GeneralConfig.PERF_METRICS_ENABLED; import static datadog.trace.api.config.GeneralConfig.PRIMARY_TAG; @@ -936,7 +934,6 @@ public static String getHostName() { private final String triageReportDir; private final boolean startupLogsEnabled; - private final boolean jsonLogsEnabled; private final String configFileStatus; private final IdGenerationStrategy idGenerationStrategy; @@ -2109,7 +2106,6 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) startupLogsEnabled = configProvider.getBoolean(STARTUP_LOGS_ENABLED, DEFAULT_STARTUP_LOGS_ENABLED); - jsonLogsEnabled = configProvider.getBoolean(JSON_LOGS_ENABLED, DEFAULT_JSON_LOGS_ENABLED); cwsEnabled = configProvider.getBoolean(CWS_ENABLED, DEFAULT_CWS_ENABLED); cwsTlsRefresh = configProvider.getInteger(CWS_TLS_REFRESH, DEFAULT_CWS_TLS_REFRESH); @@ -3559,10 +3555,6 @@ public boolean isStartupLogsEnabled() { return startupLogsEnabled; } - public boolean isJsonLogsEnabled() { - return jsonLogsEnabled; - } - public boolean isCwsEnabled() { return cwsEnabled; } @@ -4754,8 +4746,6 @@ public String toString() { + triageReportDir + ", startLogsEnabled=" + startupLogsEnabled - + ", jsonLogsEnabled=" - + jsonLogsEnabled + ", configFile='" + configFileStatus + '\'' From 4ff32667e7f7fbc96bc03036343506d1909596b1 Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Thu, 14 Nov 2024 15:57:12 +0100 Subject: [PATCH 03/13] init tests + formatting --- .../java/datadog/trace/bootstrap/Agent.java | 3 +- .../logging/simplelogger/SLCompatHelper.java | 24 +++++--- .../simplelogger/SLCompatSettings.java | 3 - .../logging/ddlogger/DDLoggerTest.groovy | 1 + .../simplelogger/SLCompatHelperTest.groovy | 56 ++++++++++++++----- .../simplelogger/SLCompatSettingsTest.groovy | 2 + .../resources/slcompatsettingstest.properties | 1 + 7 files changed, 63 insertions(+), 27 deletions(-) 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 a5c1b65f08c..a0514f67a64 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 @@ -1106,8 +1106,7 @@ private static void configureLogger() { setSystemPropertyDefault(SIMPLE_LOGGER_SHOW_DATE_TIME_PROPERTY, "true"); setSystemPropertyDefault( SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY, SIMPLE_LOGGER_DATE_TIME_FORMAT_DEFAULT); - setSystemPropertyDefault( - SIMPLE_LOGGER_JSON_ENABLED_PROPERTY, "false"); + setSystemPropertyDefault(SIMPLE_LOGGER_JSON_ENABLED_PROPERTY, "false"); String logLevel; if (isDebugMode()) { diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java index 6884e67925f..5c51b09f7e0 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java @@ -1,6 +1,7 @@ package datadog.trace.logging.simplelogger; import static datadog.trace.util.Strings.escapeToJson; + import datadog.trace.logging.LogLevel; import datadog.trace.logging.LoggerHelper; import org.slf4j.Marker; @@ -35,11 +36,11 @@ public void log(LogLevel level, Marker marker, String message, Throwable t) { if (settings.showDateTime) { timeMillis = System.currentTimeMillis(); } - + System.out.println("CTE settings.jsonEnabled: " + settings.jsonEnabled); if (settings.jsonEnabled) { - logJson(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); + logJson(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); } else { - log(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); + log(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); } } @@ -146,7 +147,7 @@ void logJson( StringBuilder buf = new StringBuilder(32); buf.append("{"); - + if (timeMillis >= 0 && settings.showDateTime) { embedJsonKey(buf, "time"); settings.dateTimeFormatter.appendFormattedDate(buf, timeMillis, startTimeMillis); @@ -158,12 +159,13 @@ void logJson( } embedJsonKey(buf, "level"); + if (settings.warnLevelString != null && level == LogLevel.WARN) { - embedJsonValue(buf, settings.warnLevelString, true); + embedJsonValue(buf, wrappedValueWithBracketsIfRequested(settings.warnLevelString), true); } else if (marker != null) { - embedJsonValue(buf, marker.getName(), true); + embedJsonValue(buf, wrappedValueWithBracketsIfRequested(marker.getName()), true); } else { - embedJsonValue(buf, level.name(), true); + embedJsonValue(buf, wrappedValueWithBracketsIfRequested(level.name()), true); } if (!logName.isEmpty()) { @@ -184,7 +186,10 @@ void logJson( private void embedJson(StringBuilder buf, String key, String value, boolean withComma) { embedJsonKey(buf, key); embedJsonValue(buf, value, withComma); + } + private String wrappedValueWithBracketsIfRequested(String value) { + return settings.levelInBrackets ? '[' + value + ']' : value; } private void embedJsonKey(StringBuilder buf, String key) { @@ -197,10 +202,11 @@ private void embedJsonValue(StringBuilder buf, String value, boolean withComma) buf.append(","); } } + private void embedExceptionJson(StringBuilder buf, Throwable t) { buf.append("\"exception\":{"); - embedJson(buf, "message",escapeToJson(t.getMessage()), true); - int length = t.getStackTrace().length; + embedJson(buf, "message", escapeToJson(t.getMessage()), true); + int length = t.getStackTrace().length; if (length > 0) { buf.append("\"stackTrace\":[\""); int count = 0; diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java index a9e82dcdd42..21304bc9a09 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java @@ -1,7 +1,5 @@ package datadog.trace.logging.simplelogger; -import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; - import datadog.trace.logging.LogLevel; import datadog.trace.logging.LogReporter; import datadog.trace.logging.PrintStreamWrapper; @@ -39,7 +37,6 @@ public static final class Names { public static final String DEFAULT_LOG_LEVEL = "defaultLogLevel"; public static final String EMBED_EXCEPTION = "embedException"; public static final String CONFIGURATION_FILE = "configurationFile"; - } public static final class Keys { diff --git a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/ddlogger/DDLoggerTest.groovy b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/ddlogger/DDLoggerTest.groovy index 19bfe6c720f..d8d299439e4 100644 --- a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/ddlogger/DDLoggerTest.groovy +++ b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/ddlogger/DDLoggerTest.groovy @@ -359,6 +359,7 @@ class DDLoggerTest extends LogValidatingSpecification { (Names.SHOW_SHORT_LOG_NAME): Defaults.SHOW_SHORT_LOG_NAME, (Names.SHOW_THREAD_NAME): false, (Names.SHOW_DATE_TIME): true, + (Names.JSON_ENABLED): Defaults.JSON_ENABLED, (Names.DATE_TIME_FORMAT): "relative", (Names.DEFAULT_LOG_LEVEL): expectedLevel, (Names.EMBED_EXCEPTION): Defaults.EMBED_EXCEPTION, diff --git a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy index 2508aa62b4c..38dcaa5af52 100644 --- a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy +++ b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy @@ -1,6 +1,7 @@ package datadog.trace.logging.simplelogger import datadog.trace.logging.LogLevel +import org.slf4j.Marker import spock.lang.Shared import spock.lang.Specification @@ -139,25 +140,54 @@ class SLCompatHelperTest extends Specification { def printStream = new PrintStream(outputStream, true) def props = new Properties() def dateTimeFormatter = SLCompatSettings.DTFormatter.create(dateTFS) - def settings = new SLCompatSettings(props, props, warnS, showB, printStream, showS, showL, showT, dateTimeFormatter, showDT, LogLevel.INFO, false) + def settings = new SLCompatSettings(props, props, warnS, showB, printStream, showS, showL, showT, dateTimeFormatter, showDT, jsonE, LogLevel.INFO, false) def helper = new SLCompatHelper("foo.bar", settings) + helper.log(level, null, 0, 4711, "thread", "log", null) then: outputStream.toString() == expected where: - level | warnS | showB | showS | showL | showT | dateTFS | showDT | expected - LogLevel.WARN | null | false | false | false | false | null | false | "WARN log\n" - LogLevel.WARN | "DANGER" | false | false | false | false | null | false | "DANGER log\n" - LogLevel.INFO | "DANGER" | false | false | false | false | null | false | "INFO log\n" - LogLevel.WARN | null | true | false | false | false | null | false | "[WARN] log\n" - LogLevel.INFO | null | false | true | false | false | null | false | "INFO bar - log\n" - LogLevel.INFO | null | true | true | true | false | null | false | "[INFO] bar - log\n" - LogLevel.INFO | null | true | false | true | false | null | false | "[INFO] foo.bar - log\n" - LogLevel.INFO | null | false | false | false | true | null | false | "[thread] INFO log\n" - LogLevel.INFO | null | false | false | false | true | null | true | "4711 [thread] INFO log\n" - LogLevel.INFO | null | false | false | false | true | "yyyy-MM-dd HH:mm:ss z" | false | "[thread] INFO log\n" - LogLevel.INFO | null | false | false | false | true | "yyyy-MM-dd HH:mm:ss z" | true | "${new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(new Date(4711))} [thread] INFO log\n" + level | warnS | showB | showS | showL | showT | dateTFS | showDT | jsonE | expected + LogLevel.WARN | null | false | false | false | false | null | false | false | "WARN log\n" + LogLevel.WARN | "DANGER" | false | false | false | false | null | false | false | "DANGER log\n" + LogLevel.INFO | "DANGER" | false | false | false | false | null | false | false | "INFO log\n" + LogLevel.WARN | null | true | false | false | false | null | false | false | "[WARN] log\n" + LogLevel.INFO | null | false | true | false | false | null | false | false | "INFO bar - log\n" + LogLevel.INFO | null | true | true | true | false | null | false | false | "[INFO] bar - log\n" + LogLevel.INFO | null | true | false | true | false | null | false | false | "[INFO] foo.bar - log\n" + LogLevel.INFO | null | false | false | false | true | null | false | false | "[thread] INFO log\n" + LogLevel.INFO | null | false | false | false | true | null | true | false | "4711 [thread] INFO log\n" + LogLevel.INFO | null | false | false | false | true | "yyyy-MM-dd HH:mm:ss z" | false | false | "[thread] INFO log\n" + LogLevel.INFO | null | false | false | false | true | "yyyy-MM-dd HH:mm:ss z" | true | false | "${new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(new Date(4711))} [thread] INFO log\n" + } + + + def "test log output with JSon configuration"() { + when: + def outputStream = new ByteArrayOutputStream() + def printStream = new PrintStream(outputStream, true) + def props = new Properties() + def dateTimeFormatter = SLCompatSettings.DTFormatter.create(dateTFS) + def settings = new SLCompatSettings(props, props, warnS, showB, printStream, showS, showL, showT, dateTimeFormatter, showDT, jsonE, LogLevel.INFO, false) + def helper = new SLCompatHelper("foo.bar", settings) + + helper. log(level, null, "log", null) + + then: + outputStream.toString() == expected + + where: + level | warnS | showB | showS | showL | showT | dateTFS | showDT | jsonE | expected + LogLevel.WARN | null | false | false | false | false | null | false | false | "WARN log\n" + LogLevel.WARN | "DANGER" | false | false | false | false | null | false | true | "{\"level\":\"DANGER\",\"message\":\"log\"}\n" + LogLevel.INFO | "DANGER" | false | false | false | false | null | false | true | "{\"level\":\"INFO\",\"message\":\"log\"}\n" + LogLevel.WARN | null | true | false | false | false | null | false | true | "{\"level\":\"[WARN]\",\"message\":\"log\"}\n" + LogLevel.INFO | null | false | true | false | false | null | false | true | "{\"level\":\"INFO\",\"loggerName\":\"bar\",\"message\":\"log\"}\n" + LogLevel.INFO | null | true | true | true | false | null | false | true | "{\"level\":\"[INFO]\",\"loggerName\":\"bar\",\"message\":\"log\"}\n" + LogLevel.INFO | null | true | false | true | false | null | false | true | "{\"level\":\"[INFO]\",\"loggerName\":\"foo.bar\",\"message\":\"log\"}\n" + LogLevel.INFO | null | false | false | false | true | null | false | true | "{\"threadName\":\"Test worker\",\"level\":\"INFO\",\"message\":\"log\"}\n" + LogLevel.INFO | null | false | false | false | true | "yyyy-MM-dd HH:mm:ss z" | false | true | "{\"threadName\":\"Test worker\",\"level\":\"INFO\",\"message\":\"log\"}\n" } } diff --git a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatSettingsTest.groovy b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatSettingsTest.groovy index cfb57387adf..2b8a3cda8ec 100644 --- a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatSettingsTest.groovy +++ b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatSettingsTest.groovy @@ -71,6 +71,7 @@ class SLCompatSettingsTest extends Specification { settings.dateTimeFormatter.class == SLCompatSettings.DiffDTFormatter settings.showDateTime == false settings.defaultLogLevel == LogLevel.INFO + settings.jsonEnabled == false } def "test file properties"() { @@ -91,6 +92,7 @@ class SLCompatSettingsTest extends Specification { formatted.toString() == new SimpleDateFormat("'['yy-dd-MM HH:mm:ss:SSS Z']'").format(new Date(4711 << 20)) settings.showDateTime == true settings.defaultLogLevel == LogLevel.DEBUG + settings.jsonEnabled == true } def "test log file creation"() { diff --git a/dd-java-agent/agent-logging/src/test/resources/slcompatsettingstest.properties b/dd-java-agent/agent-logging/src/test/resources/slcompatsettingstest.properties index 187f2eb8ae3..2befd40e19d 100644 --- a/dd-java-agent/agent-logging/src/test/resources/slcompatsettingstest.properties +++ b/dd-java-agent/agent-logging/src/test/resources/slcompatsettingstest.properties @@ -7,3 +7,4 @@ datadog.slf4j.simpleLogger.showThreadName = false datadog.slf4j.simpleLogger.dateTimeFormat = '['yy-dd-MM HH:mm:ss:SSS Z']' datadog.slf4j.simpleLogger.showDateTime = true datadog.slf4j.simpleLogger.defaultLogLevel = DEBUG +datadog.slf4j.simpleLogger.json.enabled = true From 388288190c4aee29ec980fb0aa9fb9008a3b4b8c Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Tue, 19 Nov 2024 14:22:22 +0100 Subject: [PATCH 04/13] Adapt JSON keys to DD LOG UI --- .../java/datadog/trace/bootstrap/Agent.java | 20 ++++++++++++++++--- .../logging/simplelogger/SLCompatHelper.java | 8 ++++---- 2 files changed, 21 insertions(+), 7 deletions(-) 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 a0514f67a64..1ac5f06fce0 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 @@ -71,6 +71,8 @@ public class Agent { "datadog.slf4j.simpleLogger.showDateTime"; private static final String SIMPLE_LOGGER_JSON_ENABLED_PROPERTY = "datadog.slf4j.simpleLogger.json.enabled"; + private static final String SIMPLE_LOGGER_DATE_TIME_FORMAT_JSON_DEFAULT = + "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; private static final String SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY = "datadog.slf4j.simpleLogger.dateTimeFormat"; private static final String SIMPLE_LOGGER_DATE_TIME_FORMAT_DEFAULT = @@ -1104,9 +1106,21 @@ private static synchronized void startDebuggerAgent( private static void configureLogger() { setSystemPropertyDefault(SIMPLE_LOGGER_SHOW_DATE_TIME_PROPERTY, "true"); - setSystemPropertyDefault( - SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY, SIMPLE_LOGGER_DATE_TIME_FORMAT_DEFAULT); - setSystemPropertyDefault(SIMPLE_LOGGER_JSON_ENABLED_PROPERTY, "false"); + + String simpleLoggerJsonInSystemPropertySetByUser = + System.getProperty(SIMPLE_LOGGER_JSON_ENABLED_PROPERTY); + String simpleLoggerJsonInEnvVarSetByUser = ddGetEnv(SIMPLE_LOGGER_JSON_ENABLED_PROPERTY); + if ((simpleLoggerJsonInSystemPropertySetByUser != null + && simpleLoggerJsonInSystemPropertySetByUser.equalsIgnoreCase("true")) + || (simpleLoggerJsonInEnvVarSetByUser != null + && simpleLoggerJsonInEnvVarSetByUser.equalsIgnoreCase("true"))) { + setSystemPropertyDefault( + SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY, SIMPLE_LOGGER_DATE_TIME_FORMAT_JSON_DEFAULT); + } else { + setSystemPropertyDefault( + SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY, SIMPLE_LOGGER_DATE_TIME_FORMAT_DEFAULT); + setSystemPropertyDefault(SIMPLE_LOGGER_JSON_ENABLED_PROPERTY, "false"); + } String logLevel; if (isDebugMode()) { diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java index 5c51b09f7e0..5db46d81287 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java @@ -36,7 +36,6 @@ public void log(LogLevel level, Marker marker, String message, Throwable t) { if (settings.showDateTime) { timeMillis = System.currentTimeMillis(); } - System.out.println("CTE settings.jsonEnabled: " + settings.jsonEnabled); if (settings.jsonEnabled) { logJson(level, marker, SLCompatFactory.START_TIME, timeMillis, message, t); } else { @@ -147,15 +146,16 @@ void logJson( StringBuilder buf = new StringBuilder(32); buf.append("{"); + embedJson(buf, "origin", "dd.trace", true); if (timeMillis >= 0 && settings.showDateTime) { - embedJsonKey(buf, "time"); + embedJsonKey(buf, "date"); settings.dateTimeFormatter.appendFormattedDate(buf, timeMillis, startTimeMillis); buf.append("\","); } if (settings.showThreadName && threadName != null) { - embedJson(buf, "threadName", threadName, true); + embedJson(buf, "logger.thread_name", threadName, true); } embedJsonKey(buf, "level"); @@ -169,7 +169,7 @@ void logJson( } if (!logName.isEmpty()) { - embedJson(buf, "loggerName", logName, true); + embedJson(buf, "logger.name", logName, true); } embedJson(buf, "message", message, false); From 4e902493a16d72451240f1120cd86a68d040c798 Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Wed, 20 Nov 2024 15:00:22 +0100 Subject: [PATCH 05/13] add some tests --- .../simplelogger/SLCompatHelperTest.groovy | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy index 38dcaa5af52..ebb1c2bd607 100644 --- a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy +++ b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy @@ -164,7 +164,8 @@ class SLCompatHelperTest extends Specification { } - def "test log output with JSon configuration"() { + + def "test log output with Json configuration key"() { when: def outputStream = new ByteArrayOutputStream() def printStream = new PrintStream(outputStream, true) @@ -173,7 +174,8 @@ class SLCompatHelperTest extends Specification { def settings = new SLCompatSettings(props, props, warnS, showB, printStream, showS, showL, showT, dateTimeFormatter, showDT, jsonE, LogLevel.INFO, false) def helper = new SLCompatHelper("foo.bar", settings) - helper. log(level, null, "log", null) + // helper.log is where we split between logs and JSON logs + helper.log(level, null, "log", null) then: outputStream.toString() == expected @@ -181,13 +183,51 @@ class SLCompatHelperTest extends Specification { where: level | warnS | showB | showS | showL | showT | dateTFS | showDT | jsonE | expected LogLevel.WARN | null | false | false | false | false | null | false | false | "WARN log\n" - LogLevel.WARN | "DANGER" | false | false | false | false | null | false | true | "{\"level\":\"DANGER\",\"message\":\"log\"}\n" - LogLevel.INFO | "DANGER" | false | false | false | false | null | false | true | "{\"level\":\"INFO\",\"message\":\"log\"}\n" - LogLevel.WARN | null | true | false | false | false | null | false | true | "{\"level\":\"[WARN]\",\"message\":\"log\"}\n" - LogLevel.INFO | null | false | true | false | false | null | false | true | "{\"level\":\"INFO\",\"loggerName\":\"bar\",\"message\":\"log\"}\n" - LogLevel.INFO | null | true | true | true | false | null | false | true | "{\"level\":\"[INFO]\",\"loggerName\":\"bar\",\"message\":\"log\"}\n" - LogLevel.INFO | null | true | false | true | false | null | false | true | "{\"level\":\"[INFO]\",\"loggerName\":\"foo.bar\",\"message\":\"log\"}\n" - LogLevel.INFO | null | false | false | false | true | null | false | true | "{\"threadName\":\"Test worker\",\"level\":\"INFO\",\"message\":\"log\"}\n" - LogLevel.INFO | null | false | false | false | true | "yyyy-MM-dd HH:mm:ss z" | false | true | "{\"threadName\":\"Test worker\",\"level\":\"INFO\",\"message\":\"log\"}\n" + LogLevel.WARN | "DANGER" | false | false | false | false | null | false | true | "{\"origin\":\"dd.trace\",\"level\":\"DANGER\",\"message\":\"log\"}\n" + } + + def "test log output in Json"() { + when: + def outputStream = new ByteArrayOutputStream() + def printStream = new PrintStream(outputStream, true) + def props = new Properties() + def dateTimeFormatter = SLCompatSettings.DTFormatter.create(dateTFS) + def settings = new SLCompatSettings(props, props, warnS, showB, printStream, showS, showL, showT, dateTimeFormatter, showDT, jsonE, LogLevel.INFO, false) + def helper = new SLCompatHelper("foo.bar", settings) + + helper.logJson(level,null,0,4711,"thread","log", null) + + then: + outputStream.toString() == expected + + where: + level | warnS | showB | showS | showL | showT | dateTFS | showDT | jsonE | expected + LogLevel.WARN | "DANGER" | false | false | false | false | null | false | true | "{\"origin\":\"dd.trace\",\"level\":\"DANGER\",\"message\":\"log\"}\n" + LogLevel.INFO | "DANGER" | false | false | false | false | null | false | true | "{\"origin\":\"dd.trace\",\"level\":\"INFO\",\"message\":\"log\"}\n" + LogLevel.WARN | null | true | false | false | false | null | false | true | "{\"origin\":\"dd.trace\",\"level\":\"[WARN]\",\"message\":\"log\"}\n" + LogLevel.INFO | null | false | true | false | false | null | false | true | "{\"origin\":\"dd.trace\",\"level\":\"INFO\",\"logger.name\":\"bar\",\"message\":\"log\"}\n" + LogLevel.INFO | null | true | true | true | false | null | false | true | "{\"origin\":\"dd.trace\",\"level\":\"[INFO]\",\"logger.name\":\"bar\",\"message\":\"log\"}\n" + LogLevel.INFO | null | true | false | true | false | null | false | true | "{\"origin\":\"dd.trace\",\"level\":\"[INFO]\",\"logger.name\":\"foo.bar\",\"message\":\"log\"}\n" + LogLevel.INFO | null | false | false | false | true | null | false | true | "{\"origin\":\"dd.trace\",\"logger.thread_name\":\"thread\",\"level\":\"INFO\",\"message\":\"log\"}\n" + LogLevel.INFO | null | false | false | false | true | "yyyy-MM-dd HH:mm:ss z" | false | true | "{\"origin\":\"dd.trace\",\"logger.thread_name\":\"thread\",\"level\":\"INFO\",\"message\":\"log\"}\n" + LogLevel.INFO | null | false | false | false | true | "yyyy-MM-dd HH:mm:ss z" | true | true | "{\"origin\":\"dd.trace\",\"date\":\"${new SimpleDateFormat(dateTFS).format(new Date(4711))}\",\"logger.thread_name\":\"thread\",\"level\":\"INFO\",\"message\":\"log\"}\n" + } + + + def "test logging with an embedded exception in Json"() { + setup: + def outputStream = new ByteArrayOutputStream() + def printStream = new PrintStream(outputStream, true) + def props = new Properties() + def dateTimeFormatter = SLCompatSettings.DTFormatter.create("yyyy-MM-dd HH:mm:ss z") + def settings = new SLCompatSettings(props, props, null, false, printStream, false,true,false, dateTimeFormatter, false, true, LogLevel.INFO, true) + def helper = new SLCompatHelper("foo", settings) + try { + throw new IOException("wrong") + } catch(Exception exception) { + helper.log(LogLevel.INFO, null, "log", exception) + } + expect: + outputStream.toString() ==~ /^\{"origin":"dd.trace","level":"INFO","logger.name":"foo","message":"log","exception":\{"message":"wrong","stackTrace":\[.*\]\}\}\n$/ } } From df21ed35543dd70d697a53f661599095c203b212 Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Thu, 21 Nov 2024 15:51:43 +0100 Subject: [PATCH 06/13] remove empty lines --- internal-api/src/main/java/datadog/trace/api/Config.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index aaea2e81227..0842b1af76a 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -599,14 +599,12 @@ public static String getHostName() { private final String runtimeVersion; private final String applicationKey; - /** * Note: this has effect only on profiling site. Traces are sent to Datadog agent and are not * affected by this setting. If CI Visibility is used with agentless mode, api key is used when * sending data (including traces) to backend */ private final String apiKey; - /** * Note: this has effect only on profiling site. Traces are sent to Datadog agent and are not * affected by this setting. From 4da342e7c49404ef77c9c922bf689adf7b87a265 Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Thu, 12 Dec 2024 16:38:22 +0100 Subject: [PATCH 07/13] use new JSON writer component --- dd-java-agent/agent-logging/build.gradle | 1 + .../logging/simplelogger/SLCompatHelper.java | 86 ++++++++----------- 2 files changed, 36 insertions(+), 51 deletions(-) diff --git a/dd-java-agent/agent-logging/build.gradle b/dd-java-agent/agent-logging/build.gradle index 411e3573702..f4430f347ff 100644 --- a/dd-java-agent/agent-logging/build.gradle +++ b/dd-java-agent/agent-logging/build.gradle @@ -23,4 +23,5 @@ dependencies { // This is fine since this project is shadowed into the agent-jar by dd-java-agent:agent-bootstrap api libs.slf4j api project(':internal-api') + implementation project(':components:json') } diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java index 5db46d81287..e3ed6187a23 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java @@ -1,9 +1,13 @@ package datadog.trace.logging.simplelogger; -import static datadog.trace.util.Strings.escapeToJson; +// import static datadog.trace.util.Strings.escapeToJson; +import datadog.json.JsonWriter; import datadog.trace.logging.LogLevel; import datadog.trace.logging.LoggerHelper; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; import org.slf4j.Marker; /** @@ -143,83 +147,63 @@ void logJson( String threadName, String message, Throwable t) { - StringBuilder buf = new StringBuilder(32); - buf.append("{"); - embedJson(buf, "origin", "dd.trace", true); + JsonWriter writer = new JsonWriter(); + writer.beginObject(); + writer.name("origin").value("dd.trace"); if (timeMillis >= 0 && settings.showDateTime) { - embedJsonKey(buf, "date"); + writer.name("date"); + StringBuilder buf = new StringBuilder(32); settings.dateTimeFormatter.appendFormattedDate(buf, timeMillis, startTimeMillis); - buf.append("\","); + writer.value(buf.toString()); } if (settings.showThreadName && threadName != null) { - embedJson(buf, "logger.thread_name", threadName, true); + writer.name("logger.thread_name").value(threadName); } - embedJsonKey(buf, "level"); + writer.name("level"); if (settings.warnLevelString != null && level == LogLevel.WARN) { - embedJsonValue(buf, wrappedValueWithBracketsIfRequested(settings.warnLevelString), true); + writer.value(wrappedValueWithBracketsIfRequested(settings.warnLevelString)); } else if (marker != null) { - embedJsonValue(buf, wrappedValueWithBracketsIfRequested(marker.getName()), true); + writer.value(wrappedValueWithBracketsIfRequested(marker.getName())); } else { - embedJsonValue(buf, wrappedValueWithBracketsIfRequested(level.name()), true); + writer.value(wrappedValueWithBracketsIfRequested(level.name())); } if (!logName.isEmpty()) { - embedJson(buf, "logger.name", logName, true); + writer.name("logger.name").value(logName); } - embedJson(buf, "message", message, false); + writer.name("message").value(message); if (t != null) { - buf.append(","); - embedExceptionJson(buf, t); + embedExceptionJson(writer, t); } - - buf.append("}"); - - settings.printStream.println(buf); - } - - private void embedJson(StringBuilder buf, String key, String value, boolean withComma) { - embedJsonKey(buf, key); - embedJsonValue(buf, value, withComma); + writer.endObject(); + settings.printStream.println(writer.toString()); } private String wrappedValueWithBracketsIfRequested(String value) { return settings.levelInBrackets ? '[' + value + ']' : value; } - private void embedJsonKey(StringBuilder buf, String key) { - buf.append("\"").append(escapeToJson(key)).append("\":\""); - } - - private void embedJsonValue(StringBuilder buf, String value, boolean withComma) { - buf.append(escapeToJson(value)).append("\""); - if (withComma) { - buf.append(","); - } - } - - private void embedExceptionJson(StringBuilder buf, Throwable t) { - buf.append("\"exception\":{"); - embedJson(buf, "message", escapeToJson(t.getMessage()), true); - int length = t.getStackTrace().length; - if (length > 0) { - buf.append("\"stackTrace\":[\""); - int count = 0; - for (StackTraceElement element : t.getStackTrace()) { - count += 1; - buf.append(escapeToJson(element.toString())); - if (count != length) { - buf.append("\",\""); - } + private void embedExceptionJson(JsonWriter writer, Throwable t) { + writer.name("exception"); + writer.beginObject(); + writer.name("message").value(t.getMessage()); + if (t.getStackTrace().length > 0) { + List stackTraceElementList = Arrays.asList(t.getStackTrace()); + Iterator it = stackTraceElementList.iterator(); + writer.name("stackTrace"); + writer.beginArray(); + while (it.hasNext()) { + StackTraceElement element = it.next(); + writer.value(element.toString()); } - buf.append("\"]"); + writer.endArray(); + writer.endObject(); } - - buf.append("}"); } } From e46d6c2b035af70ad8210d45ffc34565267c6dfd Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Thu, 12 Dec 2024 16:49:27 +0100 Subject: [PATCH 08/13] remove unnecessary toString() --- .../java/datadog/trace/logging/simplelogger/SLCompatHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java index e3ed6187a23..351d5025935 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java @@ -182,7 +182,7 @@ void logJson( embedExceptionJson(writer, t); } writer.endObject(); - settings.printStream.println(writer.toString()); + settings.printStream.println(writer); } private String wrappedValueWithBracketsIfRequested(String value) { From 5593f279100fd27f08f46913b053d1cc7d71a2e3 Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Thu, 12 Dec 2024 17:17:06 +0100 Subject: [PATCH 09/13] delete useless file --- newfilehere | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 newfilehere diff --git a/newfilehere b/newfilehere deleted file mode 100644 index e69de29bb2d..00000000000 From 4f4a1b0be2b0e0ede5691a60cbf815c0e538ed9e Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Thu, 12 Dec 2024 17:49:21 +0100 Subject: [PATCH 10/13] clean --- .../java/datadog/trace/logging/simplelogger/SLCompatHelper.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java index 351d5025935..cce8bba29c7 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatHelper.java @@ -1,7 +1,5 @@ package datadog.trace.logging.simplelogger; -// import static datadog.trace.util.Strings.escapeToJson; - import datadog.json.JsonWriter; import datadog.trace.logging.LogLevel; import datadog.trace.logging.LoggerHelper; From e4c4b13fc4ba496c64a2b4be66c5eb3daddc8e3c Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Fri, 27 Dec 2024 17:12:18 +0100 Subject: [PATCH 11/13] rename property + remove env var check --- .../src/main/java/datadog/trace/bootstrap/Agent.java | 9 +++------ .../trace/logging/simplelogger/SLCompatSettings.java | 2 +- .../src/test/resources/slcompatsettingstest.properties | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) 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 96d0879dd3d..c9c7264e2b7 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 @@ -70,7 +70,7 @@ public class Agent { private static final String SIMPLE_LOGGER_SHOW_DATE_TIME_PROPERTY = "datadog.slf4j.simpleLogger.showDateTime"; private static final String SIMPLE_LOGGER_JSON_ENABLED_PROPERTY = - "datadog.slf4j.simpleLogger.json.enabled"; + "datadog.slf4j.simpleLogger.jsonEnabled"; private static final String SIMPLE_LOGGER_DATE_TIME_FORMAT_JSON_DEFAULT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; private static final String SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY = @@ -1116,14 +1116,11 @@ private static synchronized void startDebuggerAgent( private static void configureLogger() { setSystemPropertyDefault(SIMPLE_LOGGER_SHOW_DATE_TIME_PROPERTY, "true"); - String simpleLoggerJsonInSystemPropertySetByUser = System.getProperty(SIMPLE_LOGGER_JSON_ENABLED_PROPERTY); - String simpleLoggerJsonInEnvVarSetByUser = ddGetEnv(SIMPLE_LOGGER_JSON_ENABLED_PROPERTY); + if ((simpleLoggerJsonInSystemPropertySetByUser != null - && simpleLoggerJsonInSystemPropertySetByUser.equalsIgnoreCase("true")) - || (simpleLoggerJsonInEnvVarSetByUser != null - && simpleLoggerJsonInEnvVarSetByUser.equalsIgnoreCase("true"))) { + && simpleLoggerJsonInSystemPropertySetByUser.equalsIgnoreCase("true"))) { setSystemPropertyDefault( SIMPLE_LOGGER_DATE_TIME_FORMAT_PROPERTY, SIMPLE_LOGGER_DATE_TIME_FORMAT_JSON_DEFAULT); } else { diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java index 21304bc9a09..6b75feb134d 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java @@ -33,7 +33,7 @@ public static final class Names { public static final String SHOW_THREAD_NAME = "showThreadName"; public static final String DATE_TIME_FORMAT = "dateTimeFormat"; public static final String SHOW_DATE_TIME = "showDateTime"; - public static final String JSON_ENABLED = "json.enabled"; + public static final String JSON_ENABLED = "jsonEnabled"; public static final String DEFAULT_LOG_LEVEL = "defaultLogLevel"; public static final String EMBED_EXCEPTION = "embedException"; public static final String CONFIGURATION_FILE = "configurationFile"; diff --git a/dd-java-agent/agent-logging/src/test/resources/slcompatsettingstest.properties b/dd-java-agent/agent-logging/src/test/resources/slcompatsettingstest.properties index 2befd40e19d..9ac2e8e3bd6 100644 --- a/dd-java-agent/agent-logging/src/test/resources/slcompatsettingstest.properties +++ b/dd-java-agent/agent-logging/src/test/resources/slcompatsettingstest.properties @@ -7,4 +7,4 @@ datadog.slf4j.simpleLogger.showThreadName = false datadog.slf4j.simpleLogger.dateTimeFormat = '['yy-dd-MM HH:mm:ss:SSS Z']' datadog.slf4j.simpleLogger.showDateTime = true datadog.slf4j.simpleLogger.defaultLogLevel = DEBUG -datadog.slf4j.simpleLogger.json.enabled = true +datadog.slf4j.simpleLogger.jsonEnabled = true From 1179ee5c35278d706de3f9ac12af542f5bfc9dd0 Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Mon, 30 Dec 2024 16:54:31 +0100 Subject: [PATCH 12/13] remove unused import --- .../datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy index ebb1c2bd607..31084ee6494 100644 --- a/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy +++ b/dd-java-agent/agent-logging/src/test/groovy/datadog/trace/logging/simplelogger/SLCompatHelperTest.groovy @@ -1,7 +1,6 @@ package datadog.trace.logging.simplelogger import datadog.trace.logging.LogLevel -import org.slf4j.Marker import spock.lang.Shared import spock.lang.Specification From e85525e12ccd755f9ce6d03af2ffd5f6424a2ade Mon Sep 17 00:00:00 2001 From: Cecile Terpin <“cecile.terpin@datadoghq.com”> Date: Wed, 8 Jan 2025 18:09:02 +0100 Subject: [PATCH 13/13] api is enough --- dd-java-agent/agent-logging/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/agent-logging/build.gradle b/dd-java-agent/agent-logging/build.gradle index f4430f347ff..d8c277dfa83 100644 --- a/dd-java-agent/agent-logging/build.gradle +++ b/dd-java-agent/agent-logging/build.gradle @@ -23,5 +23,5 @@ dependencies { // This is fine since this project is shadowed into the agent-jar by dd-java-agent:agent-bootstrap api libs.slf4j api project(':internal-api') - implementation project(':components:json') + api project(':components:json') }