InstrumentationConfig part 5: library logging appenders (#6321)
* InstrumentationConfig part 5: library logging appenders * Logback * remove log4j hackery * fix tests * Remove unused Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
parent
96cac8184c
commit
257009f944
|
@ -5,10 +5,14 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.log4j.appender.v2_17;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogBuilder;
|
||||
import io.opentelemetry.instrumentation.log4j.appender.v2_17.internal.ContextDataAccessor;
|
||||
import io.opentelemetry.instrumentation.log4j.appender.v2_17.internal.LogEventMapper;
|
||||
import io.opentelemetry.javaagent.bootstrap.AgentLogEmitterProvider;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -19,8 +23,29 @@ import org.apache.logging.log4j.message.Message;
|
|||
|
||||
public final class Log4jHelper {
|
||||
|
||||
private static final LogEventMapper<Map<String, String>> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE);
|
||||
private static final LogEventMapper<Map<String, String>> mapper;
|
||||
|
||||
static {
|
||||
InstrumentationConfig config = InstrumentationConfig.get();
|
||||
|
||||
boolean captureExperimentalAttributes =
|
||||
config.getBoolean("otel.instrumentation.log4j-appender.experimental-log-attributes", false);
|
||||
boolean captureMapMessageAttributes =
|
||||
config.getBoolean(
|
||||
"otel.instrumentation.log4j-appender.experimental.capture-map-message-attributes",
|
||||
false);
|
||||
List<String> captureContextDataAttributes =
|
||||
config.getList(
|
||||
"otel.instrumentation.log4j-appender.experimental.capture-context-data-attributes",
|
||||
emptyList());
|
||||
|
||||
mapper =
|
||||
new LogEventMapper<>(
|
||||
ContextDataAccessorImpl.INSTANCE,
|
||||
captureExperimentalAttributes,
|
||||
captureMapMessageAttributes,
|
||||
captureContextDataAttributes);
|
||||
}
|
||||
|
||||
public static void capture(Logger logger, Level level, Message message, Throwable throwable) {
|
||||
String instrumentationName = logger.getName();
|
||||
|
|
|
@ -12,9 +12,3 @@ dependencies {
|
|||
testImplementation("io.opentelemetry:opentelemetry-sdk-logs")
|
||||
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
|
||||
}
|
||||
|
||||
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=*")
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.log4j.appender.v2_17;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogBuilder;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogEmitterProvider;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogEmitterProviderHolder;
|
||||
|
@ -13,9 +15,13 @@ import io.opentelemetry.instrumentation.log4j.appender.v2_17.internal.LogEventMa
|
|||
import io.opentelemetry.instrumentation.sdk.appender.internal.DelegatingLogEmitterProvider;
|
||||
import io.opentelemetry.sdk.logs.SdkLogEmitterProvider;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
import org.apache.logging.log4j.ThreadContext;
|
||||
import org.apache.logging.log4j.core.Appender;
|
||||
import org.apache.logging.log4j.core.Core;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
|
@ -24,8 +30,10 @@ import org.apache.logging.log4j.core.LogEvent;
|
|||
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||
import org.apache.logging.log4j.core.config.Property;
|
||||
import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
|
||||
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
|
||||
import org.apache.logging.log4j.core.time.Instant;
|
||||
import org.apache.logging.log4j.message.MapMessage;
|
||||
import org.apache.logging.log4j.util.ReadOnlyStringMap;
|
||||
|
||||
@Plugin(
|
||||
|
@ -39,8 +47,7 @@ public class OpenTelemetryAppender extends AbstractAppender {
|
|||
private static final LogEmitterProviderHolder logEmitterProviderHolder =
|
||||
new LogEmitterProviderHolder();
|
||||
|
||||
private static final LogEventMapper<ReadOnlyStringMap> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE);
|
||||
private final LogEventMapper<ReadOnlyStringMap> mapper;
|
||||
|
||||
@PluginBuilderFactory
|
||||
public static <B extends Builder<B>> B builder() {
|
||||
|
@ -50,10 +57,43 @@ public class OpenTelemetryAppender extends AbstractAppender {
|
|||
static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B>
|
||||
implements org.apache.logging.log4j.core.util.Builder<OpenTelemetryAppender> {
|
||||
|
||||
@PluginBuilderAttribute private boolean captureExperimentalAttributes;
|
||||
@PluginBuilderAttribute private boolean captureMapMessageAttributes;
|
||||
@PluginBuilderAttribute private String captureContextDataAttributes;
|
||||
|
||||
/**
|
||||
* Sets whether experimental attributes should be set to logs. These attributes may be changed
|
||||
* or removed in the future, so only enable this if you know you do not require attributes
|
||||
* filled by this instrumentation to be stable across versions.
|
||||
*/
|
||||
public B setCaptureExperimentalAttributes(boolean captureExperimentalAttributes) {
|
||||
this.captureExperimentalAttributes = captureExperimentalAttributes;
|
||||
return asBuilder();
|
||||
}
|
||||
|
||||
/** Sets whether log4j {@link MapMessage} attributes should be copied to logs. */
|
||||
public B setCaptureMapMessageAttributes(boolean captureMapMessageAttributes) {
|
||||
this.captureMapMessageAttributes = captureMapMessageAttributes;
|
||||
return asBuilder();
|
||||
}
|
||||
|
||||
/** Configures the {@link ThreadContext} attributes that will be copied to logs. */
|
||||
public B setCaptureContextDataAttributes(String captureContextDataAttributes) {
|
||||
this.captureContextDataAttributes = captureContextDataAttributes;
|
||||
return asBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenTelemetryAppender build() {
|
||||
return new OpenTelemetryAppender(
|
||||
getName(), getLayout(), getFilter(), isIgnoreExceptions(), getPropertyArray());
|
||||
getName(),
|
||||
getLayout(),
|
||||
getFilter(),
|
||||
isIgnoreExceptions(),
|
||||
getPropertyArray(),
|
||||
captureExperimentalAttributes,
|
||||
captureMapMessageAttributes,
|
||||
captureContextDataAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,8 +102,28 @@ public class OpenTelemetryAppender extends AbstractAppender {
|
|||
Layout<? extends Serializable> layout,
|
||||
Filter filter,
|
||||
boolean ignoreExceptions,
|
||||
Property[] properties) {
|
||||
Property[] properties,
|
||||
boolean captureExperimentalAttributes,
|
||||
boolean captureMapMessageAttributes,
|
||||
String captureContextDataAttributes) {
|
||||
|
||||
super(name, filter, layout, ignoreExceptions, properties);
|
||||
this.mapper =
|
||||
new LogEventMapper<>(
|
||||
ContextDataAccessorImpl.INSTANCE,
|
||||
captureExperimentalAttributes,
|
||||
captureMapMessageAttributes,
|
||||
splitAndFilterBlanksAndNulls(captureContextDataAttributes));
|
||||
}
|
||||
|
||||
private static List<String> splitAndFilterBlanksAndNulls(String value) {
|
||||
if (value == null) {
|
||||
return emptyList();
|
||||
}
|
||||
return Arrays.stream(value.split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,15 +5,12 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.log4j.appender.v2_17.internal;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
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.instrumentation.api.internal.cache.Cache;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.io.PrintWriter;
|
||||
|
@ -33,44 +30,26 @@ 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 =
|
||||
Cache.bounded(100);
|
||||
|
||||
private final boolean captureMapMessageAttributes;
|
||||
|
||||
private final List<String> captureContextDataAttributes;
|
||||
|
||||
// cached as an optimization
|
||||
private final boolean captureAllContextDataAttributes;
|
||||
|
||||
private final ContextDataAccessor<T> contextDataAccessor;
|
||||
|
||||
public LogEventMapper(ContextDataAccessor<T> contextDataAccessor) {
|
||||
this(
|
||||
contextDataAccessor,
|
||||
Config.get()
|
||||
.getBoolean(
|
||||
"otel.instrumentation.log4j-appender.experimental.capture-map-message-attributes",
|
||||
false),
|
||||
Config.get()
|
||||
.getList(
|
||||
"otel.instrumentation.log4j-appender.experimental.capture-context-data-attributes",
|
||||
emptyList()));
|
||||
}
|
||||
private final boolean captureExperimentalAttributes;
|
||||
private final boolean captureMapMessageAttributes;
|
||||
private final List<String> captureContextDataAttributes;
|
||||
private final boolean captureAllContextDataAttributes;
|
||||
|
||||
// visible for testing
|
||||
LogEventMapper(
|
||||
public LogEventMapper(
|
||||
ContextDataAccessor<T> contextDataAccessor,
|
||||
boolean captureExperimentalAttributes,
|
||||
boolean captureMapMessageAttributes,
|
||||
List<String> captureContextDataAttributes) {
|
||||
|
||||
this.contextDataAccessor = contextDataAccessor;
|
||||
this.captureExperimentalAttributes = captureExperimentalAttributes;
|
||||
this.captureMapMessageAttributes = captureMapMessageAttributes;
|
||||
this.captureContextDataAttributes = captureContextDataAttributes;
|
||||
this.captureAllContextDataAttributes =
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.function.BiConsumer;
|
|||
import javax.annotation.Nullable;
|
||||
import org.apache.logging.log4j.message.StringMapMessage;
|
||||
import org.apache.logging.log4j.message.StructuredDataMessage;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LogEventMapperTest {
|
||||
|
||||
|
@ -32,7 +32,7 @@ class LogEventMapperTest {
|
|||
void testDefault() {
|
||||
// given
|
||||
LogEventMapper<Map<String, String>> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, emptyList());
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, false, emptyList());
|
||||
Map<String, String> contextData = new HashMap<>();
|
||||
contextData.put("key1", "value1");
|
||||
contextData.put("key2", "value2");
|
||||
|
@ -49,7 +49,7 @@ class LogEventMapperTest {
|
|||
void testSome() {
|
||||
// given
|
||||
LogEventMapper<Map<String, String>> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, singletonList("key2"));
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, false, singletonList("key2"));
|
||||
Map<String, String> contextData = new HashMap<>();
|
||||
contextData.put("key1", "value1");
|
||||
contextData.put("key2", "value2");
|
||||
|
@ -67,7 +67,7 @@ class LogEventMapperTest {
|
|||
void testAll() {
|
||||
// given
|
||||
LogEventMapper<Map<String, String>> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, singletonList("*"));
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, false, singletonList("*"));
|
||||
Map<String, String> contextData = new HashMap<>();
|
||||
contextData.put("key1", "value1");
|
||||
contextData.put("key2", "value2");
|
||||
|
@ -87,7 +87,7 @@ class LogEventMapperTest {
|
|||
void testCaptureMapMessageDisabled() {
|
||||
// given
|
||||
LogEventMapper<Map<String, String>> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, singletonList("*"));
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, false, singletonList("*"));
|
||||
|
||||
StringMapMessage message = new StringMapMessage();
|
||||
message.put("key1", "value1");
|
||||
|
@ -108,7 +108,7 @@ class LogEventMapperTest {
|
|||
void testCaptureMapMessageWithSpecialAttribute() {
|
||||
// given
|
||||
LogEventMapper<Map<String, String>> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, true, singletonList("*"));
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, true, singletonList("*"));
|
||||
|
||||
StringMapMessage message = new StringMapMessage();
|
||||
message.put("key1", "value1");
|
||||
|
@ -129,7 +129,7 @@ class LogEventMapperTest {
|
|||
void testCaptureMapMessageWithoutSpecialAttribute() {
|
||||
// given
|
||||
LogEventMapper<Map<String, String>> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, true, singletonList("*"));
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, true, singletonList("*"));
|
||||
|
||||
StringMapMessage message = new StringMapMessage();
|
||||
message.put("key1", "value1");
|
||||
|
@ -153,7 +153,7 @@ class LogEventMapperTest {
|
|||
void testCaptureStructuredDataMessage() {
|
||||
// given
|
||||
LogEventMapper<Map<String, String>> mapper =
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, true, singletonList("*"));
|
||||
new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, true, singletonList("*"));
|
||||
|
||||
StructuredDataMessage message = new StructuredDataMessage("an id", "a message", "a type");
|
||||
message.put("key1", "value1");
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
<PatternLayout
|
||||
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} traceId: %X{trace_id} spanId: %X{span_id} flags: %X{trace_flags} - %msg%n"/>
|
||||
</Console>
|
||||
<ListAppender name="ListAppender"/>
|
||||
<OpenTelemetry name="OpenTelemetryAppender"/>
|
||||
<!-- TODO run tests both with and without experimental log attributes -->
|
||||
<OpenTelemetry name="OpenTelemetryAppender" captureMapMessageAttributes="true" captureContextDataAttributes="*"/>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="TestLogger" level="All">
|
||||
<AppenderRef ref="OpenTelemetryAppender" level="All"/>
|
||||
<AppenderRef ref="ListAppender" level="All"/>
|
||||
<AppenderRef ref="Console" level="All"/>
|
||||
</Logger>
|
||||
<Root>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.logback.appender.v1_0;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.logback.appender.v1_0.LogbackSingletons.mapper;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
@ -13,7 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogEmitterProvider;
|
||||
import io.opentelemetry.instrumentation.logback.appender.v1_0.internal.LoggingEventMapper;
|
||||
import io.opentelemetry.javaagent.bootstrap.AgentLogEmitterProvider;
|
||||
import io.opentelemetry.javaagent.bootstrap.CallDepth;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
|
@ -51,7 +51,7 @@ class LogbackInstrumentation implements TypeInstrumentation {
|
|||
// logging framework delegates to another
|
||||
callDepth = CallDepth.forClass(LogEmitterProvider.class);
|
||||
if (callDepth.getAndIncrement() == 0) {
|
||||
LoggingEventMapper.INSTANCE.emit(AgentLogEmitterProvider.get(), event);
|
||||
mapper().emit(AgentLogEmitterProvider.get(), event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.logback.appender.v1_0;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import io.opentelemetry.instrumentation.logback.appender.v1_0.internal.LoggingEventMapper;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
|
||||
import java.util.List;
|
||||
|
||||
public class LogbackSingletons {
|
||||
|
||||
private static final LoggingEventMapper mapper;
|
||||
|
||||
static {
|
||||
InstrumentationConfig config = InstrumentationConfig.get();
|
||||
|
||||
boolean captureExperimentalAttributes =
|
||||
config.getBoolean(
|
||||
"otel.instrumentation.logback-appender.experimental-log-attributes", false);
|
||||
List<String> captureMdcAttributes =
|
||||
config.getList(
|
||||
"otel.instrumentation.logback-appender.experimental.capture-mdc-attributes",
|
||||
emptyList());
|
||||
|
||||
mapper = new LoggingEventMapper(captureExperimentalAttributes, captureMdcAttributes);
|
||||
}
|
||||
|
||||
public static LoggingEventMapper mapper() {
|
||||
return mapper;
|
||||
}
|
||||
}
|
|
@ -11,8 +11,3 @@ dependencies {
|
|||
testImplementation("io.opentelemetry:opentelemetry-sdk-logs")
|
||||
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
// TODO run tests both with and without experimental log attributes
|
||||
jvmArgs("-Dotel.instrumentation.logback-appender.experimental.capture-mdc-attributes=*")
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.logback.appender.v1_0;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.UnsynchronizedAppenderBase;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogEmitterProvider;
|
||||
|
@ -12,17 +14,32 @@ import io.opentelemetry.instrumentation.api.appender.internal.LogEmitterProvider
|
|||
import io.opentelemetry.instrumentation.logback.appender.v1_0.internal.LoggingEventMapper;
|
||||
import io.opentelemetry.instrumentation.sdk.appender.internal.DelegatingLogEmitterProvider;
|
||||
import io.opentelemetry.sdk.logs.SdkLogEmitterProvider;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
public class OpenTelemetryAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
|
||||
|
||||
private static final LogEmitterProviderHolder logEmitterProviderHolder =
|
||||
new LogEmitterProviderHolder();
|
||||
|
||||
private volatile boolean captureExperimentalAttributes = false;
|
||||
private volatile List<String> captureMdcAttributes = emptyList();
|
||||
|
||||
private volatile LoggingEventMapper mapper;
|
||||
|
||||
public OpenTelemetryAppender() {}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
mapper = new LoggingEventMapper(captureExperimentalAttributes, captureMdcAttributes);
|
||||
super.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(ILoggingEvent event) {
|
||||
LoggingEventMapper.INSTANCE.emit(logEmitterProviderHolder.get(), event);
|
||||
mapper.emit(logEmitterProviderHolder.get(), event);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,6 +53,24 @@ public class OpenTelemetryAppender extends UnsynchronizedAppenderBase<ILoggingEv
|
|||
logEmitterProviderHolder.set(DelegatingLogEmitterProvider.from(sdkLogEmitterProvider));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether experimental attributes should be set to logs. These attributes may be changed or
|
||||
* removed in the future, so only enable this if you know you do not require attributes filled by
|
||||
* this instrumentation to be stable across versions.
|
||||
*/
|
||||
public void setCaptureExperimentalAttributes(boolean captureExperimentalAttributes) {
|
||||
this.captureExperimentalAttributes = captureExperimentalAttributes;
|
||||
}
|
||||
|
||||
/** Configures the {@link MDC} attributes that will be copied to logs. */
|
||||
public void setCaptureMdcAttributes(String attributes) {
|
||||
if (attributes != null) {
|
||||
captureMdcAttributes = filterBlanksAndNulls(attributes.split(","));
|
||||
} else {
|
||||
captureMdcAttributes = emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets the global {@link LogEmitterProvider}. This is only meant to be used from tests which
|
||||
* need to reconfigure {@link LogEmitterProvider}.
|
||||
|
@ -43,4 +78,12 @@ public class OpenTelemetryAppender extends UnsynchronizedAppenderBase<ILoggingEv
|
|||
public static void resetSdkLogEmitterProviderForTest() {
|
||||
logEmitterProviderHolder.resetForTest();
|
||||
}
|
||||
|
||||
// copied from SDK's DefaultConfigProperties
|
||||
private static List<String> filterBlanksAndNulls(String[] values) {
|
||||
return Arrays.stream(values)
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.logback.appender.v1_0.internal;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.classic.spi.ThrowableProxy;
|
||||
|
@ -17,7 +15,6 @@ import io.opentelemetry.context.Context;
|
|||
import io.opentelemetry.instrumentation.api.appender.internal.LogBuilder;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.LogEmitterProvider;
|
||||
import io.opentelemetry.instrumentation.api.appender.internal.Severity;
|
||||
import io.opentelemetry.instrumentation.api.config.Config;
|
||||
import io.opentelemetry.instrumentation.api.internal.cache.Cache;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.io.PrintWriter;
|
||||
|
@ -32,29 +29,15 @@ import java.util.concurrent.TimeUnit;
|
|||
*/
|
||||
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 boolean captureExperimentalAttributes;
|
||||
private final List<String> captureMdcAttributes;
|
||||
|
||||
// cached as an optimization
|
||||
private final boolean captureAllMdcAttributes;
|
||||
|
||||
private LoggingEventMapper() {
|
||||
this(
|
||||
Config.get()
|
||||
.getList(
|
||||
"otel.instrumentation.logback-appender.experimental.capture-mdc-attributes",
|
||||
emptyList()));
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
LoggingEventMapper(List<String> captureMdcAttributes) {
|
||||
public LoggingEventMapper(
|
||||
boolean captureExperimentalAttributes, List<String> captureMdcAttributes) {
|
||||
this.captureExperimentalAttributes = captureExperimentalAttributes;
|
||||
this.captureMdcAttributes = captureMdcAttributes;
|
||||
this.captureAllMdcAttributes =
|
||||
captureMdcAttributes.size() == 1 && captureMdcAttributes.get(0).equals("*");
|
||||
|
|
|
@ -22,7 +22,7 @@ class LoggingEventMapperTest {
|
|||
@Test
|
||||
void testDefault() {
|
||||
// given
|
||||
LoggingEventMapper mapper = new LoggingEventMapper(emptyList());
|
||||
LoggingEventMapper mapper = new LoggingEventMapper(false, emptyList());
|
||||
Map<String, String> contextData = new HashMap<>();
|
||||
contextData.put("key1", "value1");
|
||||
contextData.put("key2", "value2");
|
||||
|
@ -38,7 +38,7 @@ class LoggingEventMapperTest {
|
|||
@Test
|
||||
void testSome() {
|
||||
// given
|
||||
LoggingEventMapper mapper = new LoggingEventMapper(singletonList("key2"));
|
||||
LoggingEventMapper mapper = new LoggingEventMapper(false, singletonList("key2"));
|
||||
Map<String, String> contextData = new HashMap<>();
|
||||
contextData.put("key1", "value1");
|
||||
contextData.put("key2", "value2");
|
||||
|
@ -55,7 +55,7 @@ class LoggingEventMapperTest {
|
|||
@Test
|
||||
void testAll() {
|
||||
// given
|
||||
LoggingEventMapper mapper = new LoggingEventMapper(singletonList("*"));
|
||||
LoggingEventMapper mapper = new LoggingEventMapper(false, singletonList("*"));
|
||||
Map<String, String> contextData = new HashMap<>();
|
||||
contextData.put("key1", "value1");
|
||||
contextData.put("key2", "value2");
|
||||
|
|
|
@ -8,12 +8,15 @@
|
|||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="OpenTelemetry" class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
|
||||
<appender name="OpenTelemetry"
|
||||
class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
|
||||
<captureExperimentalAttributes>false</captureExperimentalAttributes>
|
||||
<captureMdcAttributes>*</captureMdcAttributes>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="console"/>
|
||||
<appender-ref ref="OpenTelemetry" />
|
||||
<appender-ref ref="OpenTelemetry"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
|
Loading…
Reference in New Issue