Fix caller data lost in logback mdc library instrumentation (#12220)
This commit is contained in:
parent
103d160e71
commit
34740eef6a
|
@ -7,7 +7,7 @@ package io.opentelemetry.instrumentation.logback.mdc.v1_0;
|
||||||
|
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import ch.qos.logback.classic.spi.LoggerContextVO;
|
import ch.qos.logback.classic.spi.LoggerContextVO;
|
||||||
import ch.qos.logback.classic.spi.LoggingEventVO;
|
import ch.qos.logback.classic.spi.LoggingEvent;
|
||||||
import ch.qos.logback.core.Appender;
|
import ch.qos.logback.core.Appender;
|
||||||
import ch.qos.logback.core.UnsynchronizedAppenderBase;
|
import ch.qos.logback.core.UnsynchronizedAppenderBase;
|
||||||
import ch.qos.logback.core.spi.AppenderAttachable;
|
import ch.qos.logback.core.spi.AppenderAttachable;
|
||||||
|
@ -18,14 +18,26 @@ import io.opentelemetry.api.trace.SpanContext;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.instrumentation.api.incubator.log.LoggingContextConstants;
|
import io.opentelemetry.instrumentation.api.incubator.log.LoggingContextConstants;
|
||||||
import io.opentelemetry.instrumentation.logback.mdc.v1_0.internal.UnionMap;
|
import io.opentelemetry.instrumentation.logback.mdc.v1_0.internal.UnionMap;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class OpenTelemetryAppender extends UnsynchronizedAppenderBase<ILoggingEvent>
|
public class OpenTelemetryAppender extends UnsynchronizedAppenderBase<ILoggingEvent>
|
||||||
implements AppenderAttachable<ILoggingEvent> {
|
implements AppenderAttachable<ILoggingEvent> {
|
||||||
|
private static final Field MDC_MAP_FIELD;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Field field;
|
||||||
|
try {
|
||||||
|
field = LoggingEvent.class.getDeclaredField("mdcPropertyMap");
|
||||||
|
field.setAccessible(true);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
field = null;
|
||||||
|
}
|
||||||
|
MDC_MAP_FIELD = field;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean addBaggage;
|
private boolean addBaggage;
|
||||||
private String traceIdKey = LoggingContextConstants.TRACE_ID;
|
private String traceIdKey = LoggingContextConstants.TRACE_ID;
|
||||||
private String spanIdKey = LoggingContextConstants.SPAN_ID;
|
private String spanIdKey = LoggingContextConstants.SPAN_ID;
|
||||||
|
@ -59,11 +71,15 @@ public class OpenTelemetryAppender extends UnsynchronizedAppenderBase<ILoggingEv
|
||||||
this.traceFlagsKey = traceFlagsKey;
|
this.traceFlagsKey = traceFlagsKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILoggingEvent wrapEvent(ILoggingEvent event) {
|
private void processEvent(ILoggingEvent event) {
|
||||||
|
if (MDC_MAP_FIELD == null || event.getClass() != LoggingEvent.class) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, String> eventContext = event.getMDCPropertyMap();
|
Map<String, String> eventContext = event.getMDCPropertyMap();
|
||||||
if (eventContext != null && eventContext.containsKey(traceIdKey)) {
|
if (eventContext != null && eventContext.containsKey(traceIdKey)) {
|
||||||
// Assume already instrumented event if traceId is present.
|
// Assume already instrumented event if traceId is present.
|
||||||
return event;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> contextData = new HashMap<>();
|
Map<String, String> contextData = new HashMap<>();
|
||||||
|
@ -98,32 +114,18 @@ public class OpenTelemetryAppender extends UnsynchronizedAppenderBase<ILoggingEv
|
||||||
? new LoggerContextVO(oldVo.getName(), eventContextMap, oldVo.getBirthTime())
|
? new LoggerContextVO(oldVo.getName(), eventContextMap, oldVo.getBirthTime())
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
ILoggingEvent wrappedEvent =
|
try {
|
||||||
(ILoggingEvent)
|
MDC_MAP_FIELD.set(event, eventContextMap);
|
||||||
Proxy.newProxyInstance(
|
} catch (IllegalAccessException ignored) {
|
||||||
ILoggingEvent.class.getClassLoader(),
|
// setAccessible(true) was called on the field
|
||||||
new Class<?>[] {ILoggingEvent.class},
|
}
|
||||||
(proxy, method, args) -> {
|
((LoggingEvent) event).setLoggerContextRemoteView(vo);
|
||||||
if ("getMDCPropertyMap".equals(method.getName())) {
|
|
||||||
return eventContextMap;
|
|
||||||
} else if ("getLoggerContextVO".equals(method.getName())) {
|
|
||||||
return vo;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return method.invoke(event, args);
|
|
||||||
} catch (InvocationTargetException exception) {
|
|
||||||
throw exception.getCause();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// https://github.com/qos-ch/logback/blob/9e833ec858953a2296afdc3292f8542fc08f2a45/logback-classic/src/main/java/ch/qos/logback/classic/net/LoggingEventPreSerializationTransformer.java#L29
|
|
||||||
// LoggingEventPreSerializationTransformer accepts only subclasses of LoggingEvent and
|
|
||||||
// LoggingEventVO, here we transform our wrapped event into a LoggingEventVO
|
|
||||||
return LoggingEventVO.build(wrappedEvent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void append(ILoggingEvent event) {
|
protected void append(ILoggingEvent event) {
|
||||||
aai.appendLoopOnAppenders(wrapEvent(event));
|
processEvent(event);
|
||||||
|
aai.appendLoopOnAppenders(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -65,18 +65,20 @@ public abstract class AbstractLogbackTest {
|
||||||
|
|
||||||
assertThat(events.size()).isEqualTo(2);
|
assertThat(events.size()).isEqualTo(2);
|
||||||
assertThat(events.get(0).getMessage()).isEqualTo("log message 1");
|
assertThat(events.get(0).getMessage()).isEqualTo("log message 1");
|
||||||
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("trace_id"))).isNull();
|
assertThat(events.get(0).getMDCPropertyMap())
|
||||||
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("span_id"))).isNull();
|
.doesNotContainKeys(
|
||||||
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isNull();
|
getLoggingKey("trace_id"), getLoggingKey("span_id"), getLoggingKey("trace_flags"));
|
||||||
assertThat(events.get(0).getMDCPropertyMap().get("baggage.baggage_key"))
|
assertThat(events.get(0).getMDCPropertyMap().get("baggage.baggage_key"))
|
||||||
.isEqualTo(expectBaggage() ? "baggage_value" : null);
|
.isEqualTo(expectBaggage() ? "baggage_value" : null);
|
||||||
|
assertThat(events.get(0).getCallerData()).isNotNull();
|
||||||
|
|
||||||
assertThat(events.get(1).getMessage()).isEqualTo("log message 2");
|
assertThat(events.get(1).getMessage()).isEqualTo("log message 2");
|
||||||
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("trace_id"))).isNull();
|
assertThat(events.get(1).getMDCPropertyMap())
|
||||||
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("span_id"))).isNull();
|
.doesNotContainKeys(
|
||||||
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isNull();
|
getLoggingKey("trace_id"), getLoggingKey("span_id"), getLoggingKey("trace_flags"));
|
||||||
assertThat(events.get(1).getMDCPropertyMap().get("baggage.baggage_key"))
|
assertThat(events.get(1).getMDCPropertyMap().get("baggage.baggage_key"))
|
||||||
.isEqualTo(expectBaggage() ? "baggage_value" : null);
|
.isEqualTo(expectBaggage() ? "baggage_value" : null);
|
||||||
|
assertThat(events.get(1).getCallerData()).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -98,12 +100,16 @@ public abstract class AbstractLogbackTest {
|
||||||
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isEqualTo("01");
|
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isEqualTo("01");
|
||||||
assertThat(events.get(0).getMDCPropertyMap().get("baggage.baggage_key"))
|
assertThat(events.get(0).getMDCPropertyMap().get("baggage.baggage_key"))
|
||||||
.isEqualTo(expectBaggage() ? "baggage_value" : null);
|
.isEqualTo(expectBaggage() ? "baggage_value" : null);
|
||||||
|
assertThat(events.get(0).getCallerData()).isNotNull();
|
||||||
|
|
||||||
assertThat(events.get(1).getMessage()).isEqualTo("log message 2");
|
assertThat(events.get(1).getMessage()).isEqualTo("log message 2");
|
||||||
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("trace_id"))).isNull();
|
assertThat(events.get(1).getMDCPropertyMap())
|
||||||
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("span_id"))).isNull();
|
.doesNotContainKeys(
|
||||||
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isNull();
|
getLoggingKey("trace_id"),
|
||||||
assertThat(events.get(1).getMDCPropertyMap().get("baggage.baggage_key")).isNull();
|
getLoggingKey("span_id"),
|
||||||
|
getLoggingKey("trace_flags"),
|
||||||
|
"baggage.baggage_key");
|
||||||
|
assertThat(events.get(1).getCallerData()).isNotNull();
|
||||||
|
|
||||||
assertThat(events.get(2).getMessage()).isEqualTo("log message 3");
|
assertThat(events.get(2).getMessage()).isEqualTo("log message 3");
|
||||||
assertThat(events.get(2).getMDCPropertyMap().get(getLoggingKey("trace_id")))
|
assertThat(events.get(2).getMDCPropertyMap().get(getLoggingKey("trace_id")))
|
||||||
|
@ -113,6 +119,7 @@ public abstract class AbstractLogbackTest {
|
||||||
assertThat(events.get(2).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isEqualTo("01");
|
assertThat(events.get(2).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isEqualTo("01");
|
||||||
assertThat(events.get(2).getMDCPropertyMap().get("baggage.baggage_key"))
|
assertThat(events.get(2).getMDCPropertyMap().get("baggage.baggage_key"))
|
||||||
.isEqualTo(expectBaggage() ? "baggage_value" : null);
|
.isEqualTo(expectBaggage() ? "baggage_value" : null);
|
||||||
|
assertThat(events.get(2).getCallerData()).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
void runWithBaggage(Baggage baggage, Runnable runnable) {
|
void runWithBaggage(Baggage baggage, Runnable runnable) {
|
||||||
|
|
Loading…
Reference in New Issue