io.opentelemetry.instrumentation.logback.mdc.v1_0.OpenTelemetryAppender Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of opentelemetry-logback-mdc-1.0 Show documentation
Show all versions of opentelemetry-logback-mdc-1.0 Show documentation
Instrumentation of Java libraries using OpenTelemetry.
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.logback.mdc.v1_0;
import static io.opentelemetry.instrumentation.api.log.LoggingContextConstants.SPAN_ID;
import static io.opentelemetry.instrumentation.api.log.LoggingContextConstants.TRACE_FLAGS;
import static io.opentelemetry.instrumentation.api.log.LoggingContextConstants.TRACE_ID;
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.core.Appender;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import ch.qos.logback.core.spi.AppenderAttachable;
import ch.qos.logback.core.spi.AppenderAttachableImpl;
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.logback.mdc.v1_0.internal.UnionMap;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class OpenTelemetryAppender extends UnsynchronizedAppenderBase
implements AppenderAttachable {
private boolean addBaggage;
private final AppenderAttachableImpl aai = new AppenderAttachableImpl<>();
/**
* When set to true this will enable addition of all baggage entries to MDC. This can be done by
* adding the following to the logback.xml config for this appender. {@code
* true }
*
* @param addBaggage True if baggage should be added to MDC
*/
public void setAddBaggage(boolean addBaggage) {
this.addBaggage = addBaggage;
}
public ILoggingEvent wrapEvent(ILoggingEvent event) {
Map eventContext = event.getMDCPropertyMap();
if (eventContext != null && eventContext.containsKey(TRACE_ID)) {
// Assume already instrumented event if traceId is present.
return event;
}
Map contextData = new HashMap<>();
Context context = Context.current();
Span currentSpan = Span.fromContext(context);
if (currentSpan.getSpanContext().isValid()) {
SpanContext spanContext = currentSpan.getSpanContext();
contextData.put(TRACE_ID, spanContext.getTraceId());
contextData.put(SPAN_ID, spanContext.getSpanId());
contextData.put(TRACE_FLAGS, spanContext.getTraceFlags().asHex());
}
if (addBaggage) {
Baggage baggage = Baggage.fromContext(context);
baggage.forEach(
(key, value) ->
contextData.put(
// prefix all baggage values to avoid clashes with existing context
"baggage." + key, value.getValue()));
}
if (eventContext == null) {
eventContext = contextData;
} else {
eventContext = new UnionMap<>(eventContext, contextData);
}
Map eventContextMap = eventContext;
LoggerContextVO oldVo = event.getLoggerContextVO();
LoggerContextVO vo =
oldVo != null
? 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);
}
@Override
protected void append(ILoggingEvent event) {
aai.appendLoopOnAppenders(wrapEvent(event));
}
@Override
public void addAppender(Appender appender) {
aai.addAppender(appender);
}
@Override
public Iterator> iteratorForAppenders() {
return aai.iteratorForAppenders();
}
@Override
public Appender getAppender(String name) {
return aai.getAppender(name);
}
@Override
public boolean isAttached(Appender appender) {
return aai.isAttached(appender);
}
@Override
public void detachAndStopAllAppenders() {
aai.detachAndStopAllAppenders();
}
@Override
public boolean detachAppender(Appender appender) {
return aai.detachAppender(appender);
}
@Override
public boolean detachAppender(String name) {
return aai.detachAppender(name);
}
}