All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micrometer.tracing.otel.bridge.OtelTracer Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
/**
 * Copyright 2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micrometer.tracing.otel.bridge;

import java.util.Map;

import io.micrometer.tracing.Baggage;
import io.micrometer.tracing.BaggageInScope;
import io.micrometer.tracing.BaggageManager;
import io.micrometer.tracing.CurrentTraceContext;
import io.micrometer.tracing.ScopedSpan;
import io.micrometer.tracing.Span;
import io.micrometer.tracing.SpanCustomizer;
import io.micrometer.tracing.TraceContext;
import io.micrometer.tracing.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;

/**
 * OpenTelemetry implementation of a {@link Tracer}.
 *
 * @author Marcin Grzejszczak
 * @since 1.0.0
 */
public class OtelTracer implements Tracer {

    private final io.opentelemetry.api.trace.Tracer tracer;

    private final BaggageManager otelBaggageManager;

    private final OtelCurrentTraceContext otelCurrentTraceContext;

    private final EventPublisher publisher;

    /**
     * Creates a new instance of {@link OtelTracer}.
     * @param tracer tracer
     * @param otelCurrentTraceContext current trace context
     * @param publisher event publisher
     * @param otelBaggageManager baggage manager
     */
    public OtelTracer(io.opentelemetry.api.trace.Tracer tracer, OtelCurrentTraceContext otelCurrentTraceContext,
            EventPublisher publisher, BaggageManager otelBaggageManager) {
        this.tracer = tracer;
        this.publisher = publisher;
        this.otelBaggageManager = otelBaggageManager;
        this.otelCurrentTraceContext = otelCurrentTraceContext;
    }

    /**
     * Creates a new instance of {@link OtelTracer} with no baggage support.
     * @param tracer tracer
     * @param otelCurrentTraceContext current trace context
     * @param publisher event publisher
     */
    public OtelTracer(io.opentelemetry.api.trace.Tracer tracer, OtelCurrentTraceContext otelCurrentTraceContext,
            EventPublisher publisher) {
        this(tracer, otelCurrentTraceContext, publisher, NOOP);
    }

    @Override
    public Span nextSpan(Span parent) {
        if (parent == null) {
            return nextSpan();
        }
        OtelSpan otelSpan = (OtelSpan) parent;
        Context otelContext = otelSpan.context().context();
        Scope scope = null;
        if (otelContext != null && Context.current() != otelContext) { // This shouldn't
                                                                       // happen
            scope = otelContext.makeCurrent();
        }
        try {
            return OtelSpan.fromOtel(this.tracer.spanBuilder("")
                .setParent(OtelTraceContext.toOtelContext(parent.context()))
                .startSpan());
        }
        finally {
            if (scope != null) {
                scope.close();
            }
        }
    }

    @Override
    public Tracer.SpanInScope withSpan(Span span) {
        TraceContext traceContext = traceContext(span);
        CurrentTraceContext.Scope scope = this.otelCurrentTraceContext.maybeScope(traceContext);
        return new WrappedSpanInScope(scope);
    }

    private TraceContext traceContext(Span span) {
        if (span == null) {
            // remove any existing span/baggage data from the current state of anything
            // that might be holding on to it.
            this.publisher.publishEvent(new EventPublishingContextWrapper.ScopeClosedEvent());
            return new OtelTraceContext(io.opentelemetry.api.trace.Span.getInvalid());
        }
        else if (span instanceof OtelSpan) {
            return span.context();
        }
        return new OtelTraceContext(io.opentelemetry.api.trace.Span.getInvalid());
    }

    @Override
    public SpanCustomizer currentSpanCustomizer() {
        return new OtelSpanCustomizer();
    }

    @Override
    public Span currentSpan() {
        OtelTraceContext context = (OtelTraceContext) this.otelCurrentTraceContext.context();
        if (context != null && context.span != null) {
            return new OtelSpan(context);
        }
        io.opentelemetry.api.trace.Span currentSpan = io.opentelemetry.api.trace.Span.current();
        if (currentSpan == null || currentSpan.equals(io.opentelemetry.api.trace.Span.getInvalid())) {
            return null;
        }
        return new OtelSpan(currentSpan);
    }

    @Override
    public Span nextSpan() {
        return new OtelSpan(this.tracer.spanBuilder("").startSpan());
    }

    @Override
    public ScopedSpan startScopedSpan(String name) {
        io.opentelemetry.api.trace.Span span = this.tracer.spanBuilder(name).startSpan();
        return new OtelScopedSpan(span, span.makeCurrent());
    }

    @Override
    public Span.Builder spanBuilder() {
        return new OtelSpanBuilder(this.tracer);
    }

    @Override
    public TraceContext.Builder traceContextBuilder() {
        return new OtelTraceContextBuilder();
    }

    @Override
    public CurrentTraceContext currentTraceContext() {
        return this.otelCurrentTraceContext;
    }

    @Override
    public Map getAllBaggage() {
        return this.otelBaggageManager.getAllBaggage();
    }

    @Override
    public Map getAllBaggage(TraceContext traceContext) {
        return this.otelBaggageManager.getAllBaggage(traceContext);
    }

    @Override
    public Baggage getBaggage(String name) {
        return this.otelBaggageManager.getBaggage(name);
    }

    @Override
    public Baggage getBaggage(TraceContext traceContext, String name) {
        return this.otelBaggageManager.getBaggage(traceContext, name);
    }

    @Override
    @Deprecated
    public Baggage createBaggage(String name) {
        return this.otelBaggageManager.createBaggage(name);
    }

    @Override
    @Deprecated
    public Baggage createBaggage(String name, String value) {
        return this.otelBaggageManager.createBaggage(name, value);
    }

    @Override
    public BaggageInScope createBaggageInScope(String name, String value) {
        return this.otelBaggageManager.createBaggageInScope(name, value);
    }

    @Override
    public BaggageInScope createBaggageInScope(TraceContext traceContext, String name, String value) {
        return this.otelBaggageManager.createBaggageInScope(traceContext, name, value);
    }

    /**
     * Publisher of events.
     */
    public interface EventPublisher {

        /**
         * Publishes an event.
         * @param event event to publish
         */
        void publishEvent(Object event);

    }

    static class WrappedSpanInScope implements SpanInScope {

        final CurrentTraceContext.Scope scope;

        WrappedSpanInScope(CurrentTraceContext.Scope scope) {
            this.scope = scope;
        }

        @Override
        public void close() {
            this.scope.close();
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy