Add experimental thread attributes for logs (#5474)
This commit is contained in:
parent
399b39eac9
commit
627f5d3e1c
|
@ -9,3 +9,8 @@ dependencies {
|
|||
|
||||
testImplementation("org.awaitility:awaitility")
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
// TODO run tests both with and without experimental log attributes
|
||||
jvmArgs("-Dotel.instrumentation.java-util-logging.experimental-log-attributes=true")
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import io.opentelemetry.api.common.AttributesBuilder;
|
|||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogBuilder;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.Severity;
|
||||
import io.opentelemetry.instrumentation.api.config.Config;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.appender.internal.AgentLogEmitterProvider;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.io.PrintWriter;
|
||||
|
@ -24,6 +25,10 @@ public final class JavaUtilLoggingHelper {
|
|||
|
||||
private static final Formatter FORMATTER = new AccessibleFormatter();
|
||||
|
||||
private static final boolean captureExperimentalAttributes =
|
||||
Config.get()
|
||||
.getBoolean("otel.instrumentation.java-util-logging.experimental-log-attributes", false);
|
||||
|
||||
public static void capture(Logger logger, LogRecord logRecord) {
|
||||
|
||||
if (!logger.isLoggable(logRecord.getLevel())) {
|
||||
|
@ -69,11 +74,11 @@ public final class JavaUtilLoggingHelper {
|
|||
builder.setSeverityText(logRecord.getLevel().getName());
|
||||
}
|
||||
|
||||
AttributesBuilder attributes = Attributes.builder();
|
||||
|
||||
// throwable
|
||||
Throwable throwable = logRecord.getThrown();
|
||||
if (throwable != null) {
|
||||
AttributesBuilder attributes = Attributes.builder();
|
||||
|
||||
// TODO (trask) extract method for recording exception into
|
||||
// instrumentation-appender-api-internal
|
||||
attributes.put(SemanticAttributes.EXCEPTION_TYPE, throwable.getClass().getName());
|
||||
|
@ -81,10 +86,16 @@ public final class JavaUtilLoggingHelper {
|
|||
StringWriter writer = new StringWriter();
|
||||
throwable.printStackTrace(new PrintWriter(writer));
|
||||
attributes.put(SemanticAttributes.EXCEPTION_STACKTRACE, writer.toString());
|
||||
|
||||
builder.setAttributes(attributes.build());
|
||||
}
|
||||
|
||||
if (captureExperimentalAttributes) {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
attributes.put(SemanticAttributes.THREAD_NAME, currentThread.getName());
|
||||
attributes.put(SemanticAttributes.THREAD_ID, currentThread.getId());
|
||||
}
|
||||
|
||||
builder.setAttributes(attributes.build());
|
||||
|
||||
// span context
|
||||
builder.setContext(Context.current());
|
||||
}
|
||||
|
|
|
@ -54,14 +54,18 @@ class JavaUtilLoggingTest extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getSeverity()).isEqualTo(severity)
|
||||
assertThat(log.getSeverityText()).isEqualTo(severityText)
|
||||
if (exception) {
|
||||
assertThat(log.getAttributes().size()).isEqualTo(5)
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE)).isEqualTo(IllegalStateException.getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE)).isEqualTo("hello")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE)).contains(JavaUtilLoggingTest.name)
|
||||
} else {
|
||||
assertThat(log.getAttributes().size()).isEqualTo(2)
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE)).isNull()
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE)).isNull()
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE)).isNull()
|
||||
}
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
if (parent) {
|
||||
assertThat(log.getSpanContext()).isEqualTo(traces.get(0).get(0).getSpanContext())
|
||||
} else {
|
||||
|
|
|
@ -29,3 +29,8 @@ configurations {
|
|||
exclude("org.slf4j", "log4j-over-slf4j")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
// TODO run tests both with and without experimental log attributes
|
||||
jvmArgs("-Dotel.instrumentation.log4j-appender.experimental-log-attributes=true")
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import io.opentelemetry.api.common.AttributesBuilder;
|
|||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogBuilder;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.Severity;
|
||||
import io.opentelemetry.instrumentation.api.config.Config;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.appender.internal.AgentLogEmitterProvider;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.io.PrintWriter;
|
||||
|
@ -22,6 +23,10 @@ public final class Log4jHelper {
|
|||
// copied from org.apache.log4j.Level because it was only introduced in 1.2.12
|
||||
private static final int TRACE_INT = 5000;
|
||||
|
||||
private static final boolean captureExperimentalAttributes =
|
||||
Config.get()
|
||||
.getBoolean("otel.instrumentation.log4j-appender.experimental-log-attributes", false);
|
||||
|
||||
// TODO (trask) capture MDC
|
||||
public static void capture(Category logger, Priority level, Object message, Throwable throwable) {
|
||||
String instrumentationName = logger.getName();
|
||||
|
@ -42,10 +47,10 @@ public final class Log4jHelper {
|
|||
builder.setSeverityText(level.toString());
|
||||
}
|
||||
|
||||
AttributesBuilder attributes = Attributes.builder();
|
||||
|
||||
// throwable
|
||||
if (throwable != null) {
|
||||
AttributesBuilder attributes = Attributes.builder();
|
||||
|
||||
// TODO (trask) extract method for recording exception into
|
||||
// instrumentation-appender-api-internal
|
||||
attributes.put(SemanticAttributes.EXCEPTION_TYPE, throwable.getClass().getName());
|
||||
|
@ -53,10 +58,16 @@ public final class Log4jHelper {
|
|||
StringWriter writer = new StringWriter();
|
||||
throwable.printStackTrace(new PrintWriter(writer));
|
||||
attributes.put(SemanticAttributes.EXCEPTION_STACKTRACE, writer.toString());
|
||||
|
||||
builder.setAttributes(attributes.build());
|
||||
}
|
||||
|
||||
if (captureExperimentalAttributes) {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
attributes.put(SemanticAttributes.THREAD_NAME, currentThread.getName());
|
||||
attributes.put(SemanticAttributes.THREAD_ID, currentThread.getId());
|
||||
}
|
||||
|
||||
builder.setAttributes(attributes.build());
|
||||
|
||||
// span context
|
||||
builder.setContext(Context.current());
|
||||
|
||||
|
|
|
@ -52,14 +52,18 @@ class Log4j1Test extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getSeverity()).isEqualTo(severity)
|
||||
assertThat(log.getSeverityText()).isEqualTo(severityText)
|
||||
if (exception) {
|
||||
assertThat(log.getAttributes().size()).isEqualTo(5)
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE)).isEqualTo(IllegalStateException.getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE)).isEqualTo("hello")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE)).contains(Log4j1Test.name)
|
||||
} else {
|
||||
assertThat(log.getAttributes().size()).isEqualTo(2)
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE)).isNull()
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE)).isNull()
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE)).isNull()
|
||||
}
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
if (parent) {
|
||||
assertThat(log.getSpanContext()).isEqualTo(traces.get(0).get(0).getSpanContext())
|
||||
} else {
|
||||
|
|
|
@ -38,4 +38,5 @@ tasks.withType<Test>().configureEach {
|
|||
// TODO run tests both with and without experimental log attributes
|
||||
jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-map-message-attributes=true")
|
||||
jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-context-data-attributes=*")
|
||||
jvmArgs("-Dotel.instrumentation.log4j-appender.experimental-log-attributes=true")
|
||||
}
|
||||
|
|
|
@ -57,14 +57,18 @@ class Log4j2Test extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getSeverity()).isEqualTo(severity)
|
||||
assertThat(log.getSeverityText()).isEqualTo(severityText)
|
||||
if (exception) {
|
||||
assertThat(log.getAttributes().size()).isEqualTo(5)
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE)).isEqualTo(IllegalStateException.getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE)).isEqualTo("hello")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE)).contains(Log4j2Test.name)
|
||||
} else {
|
||||
assertThat(log.getAttributes().size()).isEqualTo(2)
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE)).isNull()
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE)).isNull()
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE)).isNull()
|
||||
}
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
if (parent) {
|
||||
assertThat(log.getSpanContext()).isEqualTo(traces.get(0).get(0).getSpanContext())
|
||||
} else {
|
||||
|
@ -114,9 +118,11 @@ class Log4j2Test extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getInstrumentationLibraryInfo().getName()).isEqualTo("abc")
|
||||
assertThat(log.getSeverity()).isEqualTo(Severity.INFO)
|
||||
assertThat(log.getSeverityText()).isEqualTo("INFO")
|
||||
assertThat(log.getAttributes().size()).isEqualTo(2)
|
||||
assertThat(log.getAttributes().size()).isEqualTo(4)
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("log4j.context_data.key1"))).isEqualTo("val1")
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("log4j.context_data.key2"))).isEqualTo("val2")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
}
|
||||
|
||||
def "test string map message"() {
|
||||
|
@ -138,9 +144,11 @@ class Log4j2Test extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getInstrumentationLibraryInfo().getName()).isEqualTo("abc")
|
||||
assertThat(log.getSeverity()).isEqualTo(Severity.INFO)
|
||||
assertThat(log.getSeverityText()).isEqualTo("INFO")
|
||||
assertThat(log.getAttributes().size()).isEqualTo(2)
|
||||
assertThat(log.getAttributes().size()).isEqualTo(4)
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("key1"))).isEqualTo("val1")
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("key2"))).isEqualTo("val2")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
}
|
||||
|
||||
def "test string map message with special attribute"() {
|
||||
|
@ -162,8 +170,10 @@ class Log4j2Test extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getInstrumentationLibraryInfo().getName()).isEqualTo("abc")
|
||||
assertThat(log.getSeverity()).isEqualTo(Severity.INFO)
|
||||
assertThat(log.getSeverityText()).isEqualTo("INFO")
|
||||
assertThat(log.getAttributes().size()).isEqualTo(1)
|
||||
assertThat(log.getAttributes().size()).isEqualTo(3)
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("key1"))).isEqualTo("val1")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
}
|
||||
|
||||
def "test structured data map message"() {
|
||||
|
@ -185,8 +195,10 @@ class Log4j2Test extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getInstrumentationLibraryInfo().getName()).isEqualTo("abc")
|
||||
assertThat(log.getSeverity()).isEqualTo(Severity.INFO)
|
||||
assertThat(log.getSeverityText()).isEqualTo("INFO")
|
||||
assertThat(log.getAttributes().size()).isEqualTo(2)
|
||||
assertThat(log.getAttributes().size()).isEqualTo(4)
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("key1"))).isEqualTo("val1")
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("key2"))).isEqualTo("val2")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ public final class LogEventMapper<T> {
|
|||
|
||||
private static final String SPECIAL_MAP_MESSAGE_ATTRIBUTE = "message";
|
||||
|
||||
private static final boolean captureExperimentalAttributes =
|
||||
Config.get()
|
||||
.getBoolean("otel.instrumentation.log4j-appender.experimental-log-attributes", false);
|
||||
|
||||
private static final Cache<String, AttributeKey<String>> contextDataAttributeKeyCache =
|
||||
Cache.bounded(100);
|
||||
private static final Cache<String, AttributeKey<String>> mapMessageAttributeKeyCache =
|
||||
|
@ -110,6 +114,12 @@ public final class LogEventMapper<T> {
|
|||
|
||||
captureContextDataAttributes(attributes, contextData);
|
||||
|
||||
if (captureExperimentalAttributes) {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
attributes.put(SemanticAttributes.THREAD_NAME, currentThread.getName());
|
||||
attributes.put(SemanticAttributes.THREAD_ID, currentThread.getId());
|
||||
}
|
||||
|
||||
builder.setAttributes(attributes.build());
|
||||
|
||||
builder.setContext(Context.current());
|
||||
|
|
|
@ -27,4 +27,5 @@ dependencies {
|
|||
tasks.withType<Test>().configureEach {
|
||||
// TODO run tests both with and without experimental log attributes
|
||||
jvmArgs("-Dotel.instrumentation.logback-appender.experimental.capture-mdc-attributes=*")
|
||||
jvmArgs("-Dotel.instrumentation.logback-appender.experimental-log-attributes=true")
|
||||
}
|
||||
|
|
|
@ -56,14 +56,18 @@ class LogbackTest extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getSeverity()).isEqualTo(severity)
|
||||
assertThat(log.getSeverityText()).isEqualTo(severityText)
|
||||
if (exception) {
|
||||
assertThat(log.getAttributes().size()).isEqualTo(5)
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE)).isEqualTo(IllegalStateException.getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE)).isEqualTo("hello")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE)).contains(LogbackTest.name)
|
||||
} else {
|
||||
assertThat(log.getAttributes().size()).isEqualTo(2)
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE)).isNull()
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE)).isNull()
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE)).isNull()
|
||||
}
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
if (parent) {
|
||||
assertThat(log.getSpanContext()).isEqualTo(traces.get(0).get(0).getSpanContext())
|
||||
} else {
|
||||
|
@ -119,8 +123,10 @@ class LogbackTest extends AgentInstrumentationSpecification {
|
|||
assertThat(log.getInstrumentationLibraryInfo().getName()).isEqualTo("abc")
|
||||
assertThat(log.getSeverity()).isEqualTo(Severity.INFO)
|
||||
assertThat(log.getSeverityText()).isEqualTo("INFO")
|
||||
assertThat(log.getAttributes().size()).isEqualTo(2)
|
||||
assertThat(log.getAttributes().size()).isEqualTo(4)
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("logback.mdc.key1"))).isEqualTo("val1")
|
||||
assertThat(log.getAttributes().get(AttributeKey.stringKey("logback.mdc.key2"))).isEqualTo("val2")
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_NAME)).isEqualTo(Thread.currentThread().getName())
|
||||
assertThat(log.getAttributes().get(SemanticAttributes.THREAD_ID)).isEqualTo(Thread.currentThread().getId())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,10 @@ public final class LoggingEventMapper {
|
|||
|
||||
public static final LoggingEventMapper INSTANCE = new LoggingEventMapper();
|
||||
|
||||
private static final boolean captureExperimentalAttributes =
|
||||
Config.get()
|
||||
.getBoolean("otel.instrumentation.logback-appender.experimental-log-attributes", false);
|
||||
|
||||
private static final Cache<String, AttributeKey<String>> mdcAttributeKeys = Cache.bounded(100);
|
||||
|
||||
private final List<String> captureMdcAttributes;
|
||||
|
@ -110,6 +114,12 @@ public final class LoggingEventMapper {
|
|||
|
||||
captureMdcAttributes(attributes, loggingEvent.getMDCPropertyMap());
|
||||
|
||||
if (captureExperimentalAttributes) {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
attributes.put(SemanticAttributes.THREAD_NAME, currentThread.getName());
|
||||
attributes.put(SemanticAttributes.THREAD_ID, currentThread.getId());
|
||||
}
|
||||
|
||||
builder.setAttributes(attributes.build());
|
||||
|
||||
// span context
|
||||
|
|
Loading…
Reference in New Issue