Skip to content

Instantly share code, notes, and snippets.

@mdvorak
Created April 20, 2018 12:40
Show Gist options
  • Save mdvorak/80c52b56d2587f66b6201f3cf36c4d1c to your computer and use it in GitHub Desktop.
Save mdvorak/80c52b56d2587f66b6201f3cf36c4d1c to your computer and use it in GitHub Desktop.
opentracing-contrib/java-spring-cloud#92 Standard logging integration
import io.opentracing.Scope;
import io.opentracing.ScopeManager;
import io.opentracing.Span;
import org.slf4j.MDC;
import org.springframework.lang.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class DiagnosticContextScopeManager implements ScopeManager {
private final ScopeManager scopeManager;
private final SpanDiagnosticContext spanDiagnosticContext;
public DiagnosticContextScopeManager(ScopeManager scopeManager, SpanDiagnosticContext spanDiagnosticContext) {
this.scopeManager = Objects.requireNonNull(scopeManager);
this.spanDiagnosticContext = Objects.requireNonNull(spanDiagnosticContext);
}
@Override
public Scope activate(Span span, boolean finishSpanOnClose) {
// Activate scope
Scope scope = scopeManager.activate(span, finishSpanOnClose);
Map<String, String> context = spanDiagnosticContext.create(scope.span());
// Return wrapper
return new DiagnosticContextScope(scope, context);
}
@Nullable
@Override
public Scope active() {
return scopeManager.active();
}
/**
* Wrapper class for {@link Scope}, which also closes attached {@link SpanDiagnosticContext}.
* <p>
* Created by {@link DiagnosticContextScopeManager}.
*/
public static class DiagnosticContextScope implements Scope {
private final Scope scope;
private final Map<String, String> previous = new HashMap<>();
public DiagnosticContextScope(Scope scope, Map<String, String> context) {
this.scope = scope;
// Initialize MDC
for (Map.Entry<String, String> entry : context.entrySet()) {
this.previous.put(entry.getKey(), MDC.get(entry.getKey()));
mdcReplace(entry.getKey(), entry.getValue());
}
}
@Override
public void close() {
// Close
scope.close();
// Restore previous context
for (Map.Entry<String, String> entry : previous.entrySet()) {
mdcReplace(entry.getKey(), entry.getValue());
}
}
@Nullable
@Override
public Span span() {
return scope.span();
}
private static void mdcReplace(String key, @Nullable String value) {
if (value != null) {
MDC.put(key, value);
} else {
MDC.remove(key);
}
}
}
}
import com.uber.jaeger.SpanContext;
import io.opentracing.Span;
import java.util.HashMap;
import java.util.Map;
public class JaegerDiagnosticContext implements SpanDiagnosticContext {
@Override
public Map<String, String> create(Span span) {
// Get Jaeger context
SpanContext spanContext = (SpanContext) span.context();
// Prepare context map
Map<String, String> contextMap = new HashMap<>(3);
contextMap.put("traceId", Long.toHexString(spanContext.getTraceId()));
contextMap.put("spanId", Long.toHexString(spanContext.getSpanId()));
contextMap.put("flags", Integer.toHexString(spanContext.getFlags()));
return contextMap;
}
}
import com.uber.jaeger.Tracer;
import io.opentracing.ScopeManager;
import io.opentracing.contrib.spring.cloud.starter.jaeger.TracerBuilderCustomizer;
import io.opentracing.util.ThreadLocalScopeManager;
import org.springframework.lang.NonNull;
public class JaegerDiagnosticContextTracerBuilderCustomizer implements TracerBuilderCustomizer {
private final ScopeManager scopeManager;
private final SpanDiagnosticContext spanDiagnosticContext;
public JaegerDiagnosticContextTracerBuilderCustomizer(@NonNull SpanDiagnosticContext spanDiagnosticContext) {
scopeManager = new ThreadLocalScopeManager();
this.spanDiagnosticContext = spanDiagnosticContext;
}
public JaegerDiagnosticContextTracerBuilderCustomizer(@NonNull ScopeManager scopeManager, @NonNull SpanDiagnosticContext spanDiagnosticContext) {
this.scopeManager = scopeManager;
this.spanDiagnosticContext = spanDiagnosticContext;
}
@Override
public void customize(Tracer.Builder builder) {
builder.withScopeManager(new DiagnosticContextScopeManager(scopeManager, spanDiagnosticContext));
}
}
import io.opentracing.Span;
import java.util.Map;
@FunctionalInterface
public interface SpanDiagnosticContext {
Map<String, String> create(Span span);
}
import io.opentracing.contrib.spring.cloud.starter.jaeger.TracerBuilderCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TracerDiagnosticContextAutoConfiguration {
@Configuration
@ConditionalOnClass(TracerBuilderCustomizer.class)
public static class JaegerDiagnosticContextConfiguration {
@Bean
@ConditionalOnMissingBean(SpanDiagnosticContext.class)
public JaegerDiagnosticContext jaegerDiagnosticContext() {
return new JaegerDiagnosticContext();
}
@Bean
public TracerBuilderCustomizer diagnosticContextTracerBuilderCustomizer(SpanDiagnosticContext spanDiagnosticContext) {
return new JaegerDiagnosticContextTracerBuilderCustomizer(spanDiagnosticContext);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment