You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Opentelemetry APIs are rather difficult to use - therefore I've developed the following utility method, which is part of a company internal library - so it has already been tested by some users:
Does it make sense to include some/all method in the API - or in a contrib library - or not at all?
packageorg.zalando.observability;
importstaticio.opentelemetry.api.trace.SpanKind.CONSUMER;
importstaticio.opentelemetry.api.trace.SpanKind.SERVER;
importio.opentelemetry.api.GlobalOpenTelemetry;
importio.opentelemetry.api.baggage.Baggage;
importio.opentelemetry.api.baggage.BaggageBuilder;
importio.opentelemetry.api.trace.Span;
importio.opentelemetry.api.trace.SpanBuilder;
importio.opentelemetry.api.trace.SpanKind;
importio.opentelemetry.api.trace.StatusCode;
importio.opentelemetry.api.trace.Tracer;
importio.opentelemetry.context.Context;
importio.opentelemetry.context.Scope;
importio.opentelemetry.context.propagation.TextMapGetter;
importjava.util.HashMap;
importjava.util.Locale;
importjava.util.Map;
importjava.util.function.BiConsumer;
importjava.util.function.Supplier;
importjava.util.stream.Collectors;
/** Utility methods for tracing. */publicclassTracing {
// only visible for compatibilitypublicstaticSupplier<Tracer> tracerSupplier =
() -> GlobalOpenTelemetry.get().getTracer("observability-sdk-utils");
privatestaticfinalTextMapGetter<Map<String, String>> TEXT_MAP_GETTER =
newTextMapGetter<Map<String, String>>() {
@OverridepublicIterable<String> keys(Map<String, String> carrier) {
returncarrier.values();
}
@OverridepublicStringget(Map<String, String> carrier, Stringkey) {
//noinspection ConstantConditionsreturncarrier.get(key);
}
};
privateTracing() {}
/** * Marks the current span as error. * * @param description what went wrong */publicstaticvoidsetSpanError(Stringdescription) {
setSpanError(Span.current(), description);
}
/** * Marks the current span as error. * * @param exception the exception that caused the error */publicstaticvoidsetSpanError(Throwableexception) {
setSpanError(Span.current(), exception);
}
/** * Marks the current span as error. * * @param description what went wrong * @param exception the exception that caused the error */publicstaticvoidsetSpanError(Stringdescription, Throwableexception) {
setSpanError(Span.current(), description, exception);
}
/** * Marks a span as error. * * @param span the span * @param description what went wrong */publicstaticvoidsetSpanError(Spanspan, Stringdescription) {
span.setStatus(StatusCode.ERROR, description);
}
/** * Marks a span as error. * * @param span the span * @param exception the exception that caused the error */publicstaticvoidsetSpanError(Spanspan, Throwableexception) {
span.setStatus(StatusCode.ERROR);
span.recordException(exception);
}
/** * Marks a span as error. * * @param span the span * @param description what went wrong * @param exception the exception that caused the error */publicstaticvoidsetSpanError(Spanspan, Stringdescription, Throwableexception) {
span.setStatus(StatusCode.ERROR, description);
span.recordException(exception);
}
/** * Runs a block of code with a new span - ending the span at the end and recording any exception. * * @param operation operation name of the new span */publicstatic <T> Ttrace(Stringoperation, CheckedSupplier<T> block) {
returntrace(tracerSupplier.get().spanBuilder(operation).startSpan(), block);
}
/** * Runs a block of code with a new span - ending the span at the end and recording any exception. */publicstatic <T> Ttrace(Spanspan, CheckedSupplier<T> block) {
returntraceBlock(span, block, Tracing::setSpanError);
}
privatestatic <T> TtraceBlock(
Spanspan, CheckedSupplier<T> block, BiConsumer<Span, Exception> handleException) {
try (Scopeignore = span.makeCurrent()) {
returnblock.get();
} catch (Exceptione) {
// not just RuntimeException, because Kotlin can easily throw non-RuntimeExceptionshandleException.accept(span, e);
sneakyThrow(e);
returnnull;
} catch (Throwablet) {
// if it not an Exception, it must be a throwable and we could have an OutOfMemoryError, so we// don't do anything with the spansneakyThrow(t);
returnnull;
} finally {
span.end();
}
}
/** * Trace a block of code using a server span. * * <p>The span context will be extracted from the <code>transport</code>, which you usually get * from HTTP headers of the metadata of an event you're processing. */publicstatic <T> TtraceServerSpan(
Map<String, String> transport, SpanBuilderspanBuilder, CheckedSupplier<T> block) {
returnextractAndRun(SERVER, transport, spanBuilder, block, Tracing::setSpanError);
}
/** * Trace a block of code using a server span. * * <p>The span context will be extracted from the <code>transport</code>, which you usually get * from HTTP headers of the metadata of an event you're processing. */publicstatic <T> TtraceServerSpan(
Map<String, String> transport,
SpanBuilderspanBuilder,
CheckedSupplier<T> block,
BiConsumer<Span, Exception> handleException) {
returnextractAndRun(SERVER, transport, spanBuilder, block, handleException);
}
/** * Trace a block of code using a consumer span. * * <p>The span context will be extracted from the <code>transport</code>, which you usually get * from HTTP headers of the metadata of an event you're processing. */publicstatic <T> TtraceConsumerSpan(
Map<String, String> transport, SpanBuilderspanBuilder, CheckedSupplier<T> block) {
returnextractAndRun(CONSUMER, transport, spanBuilder, block, Tracing::setSpanError);
}
/** * Trace a block of code using a consumer span. * * <p>The span context will be extracted from the <code>transport</code>, which you usually get * from HTTP headers of the metadata of an event you're processing. */publicstatic <T> TtraceConsumerSpan(
Map<String, String> transport,
SpanBuilderspanBuilder,
CheckedSupplier<T> block,
BiConsumer<Span, Exception> handleException) {
returnextractAndRun(CONSUMER, transport, spanBuilder, block, handleException);
}
privatestatic <T> TextractAndRun(
SpanKindspanKind,
Map<String, String> transport,
SpanBuilderspanBuilder,
CheckedSupplier<T> block,
BiConsumer<Span, Exception> handleException) {
try (Scopeignore = extractContext(transport).makeCurrent()) {
returntraceBlock(spanBuilder.setSpanKind(spanKind).startSpan(), block, handleException);
}
}
/** * Injects the current context into a string map, which can then be added to HTTP headers or the * metadata of an event. */publicstaticMap<String, String> injectContext() {
Map<String, String> transport = newHashMap<>();
//noinspection ConstantConditionsGlobalOpenTelemetry.get()
.getPropagators()
.getTextMapPropagator()
.inject(Context.current(), transport, Map::put);
returntransport;
}
/** * Extract the context from a string map, which you get from HTTP headers of the metadata of an * event you're processing. */publicstaticContextextractContext(Map<String, String> transport) {
Contextcurrent = Context.current();
//noinspection ConstantConditionsif (transport == null) {
returncurrent;
}
// HTTP headers are case-insensitive. As we're using Map, which is case-sensitive, we need to// normalize all the keysMap<String, String> normalizedTransport =
transport.entrySet().stream()
.collect(
Collectors.toMap(
entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue));
returnGlobalOpenTelemetry.get()
.getPropagators()
.getTextMapPropagator()
.extract(current, normalizedTransport, TEXT_MAP_GETTER);
}
/** Sets baggage items which are active in given block. */publicstatic <T> TsetBaggage(Map<String, String> baggage, CheckedSupplier<T> block) {
BaggageBuilderbuilder = Baggage.current().toBuilder();
baggage.forEach(builder::put);
Contextcontext = builder.build().storeInContext(Context.current());
try (Scopeignore = context.makeCurrent()) {
returnblock.get();
} catch (Throwablee) {
sneakyThrow(e);
returnnull;
}
}
privatestatic <EextendsThrowable> voidsneakyThrow(Throwablee) throwsE {
//noinspection uncheckedthrow (E) e;
}
}
packageorg.zalando.observability;
/** A supplier that can throw anything. */@FunctionalInterfacepublicinterfaceCheckedSupplier<T> {
Tget() throwsThrowable;
}
The text was updated successfully, but these errors were encountered:
This seems like it could be a good addition the opentelemetry-java-contrib libraries. Having a suite of helpers like this could definitely be useful, but I'm not sure we'd want to put this directly into the core repository at this point.
The Opentelemetry APIs are rather difficult to use - therefore I've developed the following utility method, which is part of a company internal library - so it has already been tested by some users:
Does it make sense to include some/all method in the API - or in a contrib library - or not at all?
The text was updated successfully, but these errors were encountered: