Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,39 @@

import ch.qos.logback.classic.spi.ILoggingEvent;
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.UnsynchronizedAppenderBase;
import ch.qos.logback.core.spi.AppenderAttachable;
import ch.qos.logback.core.spi.AppenderAttachableImpl;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.incubator.log.LoggingContextConstants;
import io.opentelemetry.instrumentation.logback.mdc.v1_0.internal.UnionMap;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class OpenTelemetryAppender extends UnsynchronizedAppenderBase<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 ignored) {
// ignored
field = null;
}
MDC_MAP_FIELD = field;
}

private boolean addBaggage;
private String traceIdKey = LoggingContextConstants.TRACE_ID;
private String spanIdKey = LoggingContextConstants.SPAN_ID;
Expand Down Expand Up @@ -59,7 +73,12 @@ public void setTraceFlagsKey(String traceFlagsKey) {
this.traceFlagsKey = traceFlagsKey;
}

public ILoggingEvent wrapEvent(ILoggingEvent event) {
@CanIgnoreReturnValue
private ILoggingEvent processEvent(ILoggingEvent event) {
if (MDC_MAP_FIELD == null || event.getClass() != LoggingEvent.class) {
return event;
}

Map<String, String> eventContext = event.getMDCPropertyMap();
if (eventContext != null && eventContext.containsKey(traceIdKey)) {
// Assume already instrumented event if traceId is present.
Expand Down Expand Up @@ -98,32 +117,19 @@ public ILoggingEvent wrapEvent(ILoggingEvent event) {
? new LoggerContextVO(oldVo.getName(), eventContextMap, oldVo.getBirthTime())
: null;

ILoggingEvent wrappedEvent =
(ILoggingEvent)
Proxy.newProxyInstance(
ILoggingEvent.class.getClassLoader(),
new Class<?>[] {ILoggingEvent.class},
(proxy, method, args) -> {
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);
try {
MDC_MAP_FIELD.set(event, eventContextMap);
} catch (IllegalAccessException ignored) {
// setAccessible(true) was called on the field
}
((LoggingEvent) event).setLoggerContextRemoteView(vo);

return event;
}

@Override
protected void append(ILoggingEvent event) {
aai.appendLoopOnAppenders(wrapEvent(event));
aai.appendLoopOnAppenders(processEvent(event));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,20 @@ void testNoIdsWhenNoSpan() {

assertThat(events.size()).isEqualTo(2);
assertThat(events.get(0).getMessage()).isEqualTo("log message 1");
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("trace_id"))).isNull();
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("span_id"))).isNull();
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isNull();
assertThat(events.get(0).getMDCPropertyMap())
.doesNotContainKeys(
getLoggingKey("trace_id"), getLoggingKey("span_id"), getLoggingKey("trace_flags"));
assertThat(events.get(0).getMDCPropertyMap().get("baggage.baggage_key"))
.isEqualTo(expectBaggage() ? "baggage_value" : null);
assertThat(events.get(0).getCallerData()).isNotNull();

assertThat(events.get(1).getMessage()).isEqualTo("log message 2");
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("trace_id"))).isNull();
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("span_id"))).isNull();
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isNull();
assertThat(events.get(1).getMDCPropertyMap())
.doesNotContainKeys(
getLoggingKey("trace_id"), getLoggingKey("span_id"), getLoggingKey("trace_flags"));
assertThat(events.get(1).getMDCPropertyMap().get("baggage.baggage_key"))
.isEqualTo(expectBaggage() ? "baggage_value" : null);
assertThat(events.get(1).getCallerData()).isNotNull();
}

@Test
Expand All @@ -98,12 +100,16 @@ void testIdsWhenSpan() {
assertThat(events.get(0).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isEqualTo("01");
assertThat(events.get(0).getMDCPropertyMap().get("baggage.baggage_key"))
.isEqualTo(expectBaggage() ? "baggage_value" : null);
assertThat(events.get(0).getCallerData()).isNotNull();

assertThat(events.get(1).getMessage()).isEqualTo("log message 2");
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("trace_id"))).isNull();
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("span_id"))).isNull();
assertThat(events.get(1).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isNull();
assertThat(events.get(1).getMDCPropertyMap().get("baggage.baggage_key")).isNull();
assertThat(events.get(1).getMDCPropertyMap())
.doesNotContainKeys(
getLoggingKey("trace_id"),
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).getMDCPropertyMap().get(getLoggingKey("trace_id")))
Expand All @@ -113,6 +119,7 @@ void testIdsWhenSpan() {
assertThat(events.get(2).getMDCPropertyMap().get(getLoggingKey("trace_flags"))).isEqualTo("01");
assertThat(events.get(2).getMDCPropertyMap().get("baggage.baggage_key"))
.isEqualTo(expectBaggage() ? "baggage_value" : null);
assertThat(events.get(2).getCallerData()).isNotNull();
}

void runWithBaggage(Baggage baggage, Runnable runnable) {
Expand Down
Loading