From 26cfa8ec2790bba5a34b2d245dd7358b5e90dfa7 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 23 Feb 2023 17:33:47 +0100 Subject: [PATCH 01/33] add extended tracer module --- .github/scripts/draft-change-log-entries.sh | 1 + extended-tracer/build.gradle.kts | 11 + .../contrib/tracer/ExtendedSpanBuilder.java | 126 ++++++++ .../contrib/tracer/ExtendedTracer.java | 61 ++++ .../opentelemetry/contrib/tracer/Tracing.java | 271 ++++++++++++++++++ settings.gradle.kts | 1 + 6 files changed, 471 insertions(+) create mode 100644 extended-tracer/build.gradle.kts create mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java create mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java create mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java diff --git a/.github/scripts/draft-change-log-entries.sh b/.github/scripts/draft-change-log-entries.sh index 55eb299b6..eff9b6e0a 100755 --- a/.github/scripts/draft-change-log-entries.sh +++ b/.github/scripts/draft-change-log-entries.sh @@ -36,6 +36,7 @@ component_names["maven-extension/"]="Maven extension" component_names["micrometer-meter-provider/"]="Micrometer MeterProvider" component_names["noop-api/"]="No-op API" component_names["processors/"]="Telemetry processors" +component_names["extended-tracer/"]="Extended Tracer" component_names["prometheus-client-bridge/"]="Prometheus client bridge" component_names["runtime-attach/"]="Runtime attach" component_names["resource-providers/"]="Resource providers" diff --git a/extended-tracer/build.gradle.kts b/extended-tracer/build.gradle.kts new file mode 100644 index 000000000..6179cc03e --- /dev/null +++ b/extended-tracer/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("otel.java-conventions") + id("otel.publish-conventions") +} + +description = "Tracing Utilities" +otelJava.moduleName.set("io.opentelemetry.contrib.extended-tracer") + +dependencies { + api("io.opentelemetry:opentelemetry-api") +} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java new file mode 100644 index 000000000..db05614f6 --- /dev/null +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java @@ -0,0 +1,126 @@ +package io.opentelemetry.contrib.tracer;/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +import java.time.Instant; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +public class ExtendedSpanBuilder implements SpanBuilder { + + private final SpanBuilder delegate; + + ExtendedSpanBuilder(SpanBuilder delegate) { + this.delegate = delegate; + } + + /** Run the provided {@link Runnable} and wrap with a {@link Span} with the provided name. */ + public void run(Runnable runnable) { + Tracing.run(startSpan(), runnable); + } + + /** Call the provided {@link Callable} and wrap with a {@link Span} with the provided name. */ + public T call(Callable callable) { + return Tracing.call(startSpan(), callable); + } + + /** + * Trace a block of code using a server span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public T traceServerSpan(Map transport, Callable callable) { + return Tracing.traceServerSpan(transport, this, callable); + } + + /** + * Trace a block of code using a consumer span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public T traceConsumerSpan( + Map transport, SpanBuilder spanBuilder, Callable callable) { + return Tracing.traceConsumerSpan(transport, this, callable); + } + + @Override + public SpanBuilder setParent(Context context) { + return delegate.setParent(context); + } + + @Override + public SpanBuilder setNoParent() { + return delegate.setNoParent(); + } + + @Override + public SpanBuilder addLink(SpanContext spanContext) { + return delegate.addLink(spanContext); + } + + @Override + public SpanBuilder addLink(SpanContext spanContext, Attributes attributes) { + return delegate.addLink(spanContext, attributes); + } + + @Override + public SpanBuilder setAttribute(String key, String value) { + return delegate.setAttribute(key, value); + } + + @Override + public SpanBuilder setAttribute(String key, long value) { + return delegate.setAttribute(key, value); + } + + @Override + public SpanBuilder setAttribute(String key, double value) { + return delegate.setAttribute(key, value); + } + + @Override + public SpanBuilder setAttribute(String key, boolean value) { + return delegate.setAttribute(key, value); + } + + @Override + public SpanBuilder setAttribute(AttributeKey key, T value) { + return delegate.setAttribute(key, value); + } + + @Override + public SpanBuilder setAllAttributes(Attributes attributes) { + return delegate.setAllAttributes(attributes); + } + + @Override + public SpanBuilder setSpanKind(SpanKind spanKind) { + return delegate.setSpanKind(spanKind); + } + + @Override + public SpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) { + return delegate.setStartTimestamp(startTimestamp, unit); + } + + @Override + public SpanBuilder setStartTimestamp(Instant startTimestamp) { + return delegate.setStartTimestamp(startTimestamp); + } + + @Override + public Span startSpan() { + return delegate.startSpan(); + } +} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java new file mode 100644 index 000000000..e799a1a70 --- /dev/null +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java @@ -0,0 +1,61 @@ +package io.opentelemetry.contrib.tracer;/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import java.util.Map; +import java.util.concurrent.Callable; + +/** Provides easy mechanisms for wrapping standard Java constructs with an OpenTelemetry Span. */ +public final class ExtendedTracer implements Tracer { + + private final Tracer delegate; + + /** Create a new {@link ExtendedTracer} that wraps the provided Tracer. */ + public static ExtendedTracer create(Tracer delegate) { + return new ExtendedTracer(delegate); + } + + private ExtendedTracer(Tracer delegate) { + this.delegate = delegate; + } + + /** Run the provided {@link Runnable} and wrap with a {@link Span} with the provided name. */ + public void run(String spanName, Runnable runnable) { + spanBuilder(spanName).run(runnable); + } + + /** Call the provided {@link Callable} and wrap with a {@link Span} with the provided name. */ + public T call(String spanName, Callable callable) { + return spanBuilder(spanName).call(callable); + } + + /** + * Injects the current context into a string map, which can then be added to HTTP headers or the + * metadata of an event. + */ + public Map injectContext() { + return Tracing.injectContext(); + } + + /** + * Extract the context from a string map, which you get from HTTP headers of the metadata of an + * event you're processing. + */ + public static Context extractContext(Map transport) { + return Tracing.extractContext(transport); + } + + /** Sets baggage items which are active in given block. */ + public static T setBaggage(Map baggage, Callable callable) { + return Tracing.setBaggage(baggage, callable); + } + + @Override + public ExtendedSpanBuilder spanBuilder(String spanName) { + return new ExtendedSpanBuilder(delegate.spanBuilder(spanName)); + } +} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java new file mode 100644 index 000000000..e38c1eaf3 --- /dev/null +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -0,0 +1,271 @@ +package io.opentelemetry.contrib.tracer;/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +import static io.opentelemetry.api.trace.SpanKind.CONSUMER; +import static io.opentelemetry.api.trace.SpanKind.SERVER; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.baggage.Baggage; +import io.opentelemetry.api.baggage.BaggageBuilder; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.context.propagation.TextMapGetter; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +public class Tracing { + + private static final TextMapGetter> TEXT_MAP_GETTER = + new TextMapGetter>() { + @Override + public Iterable keys(Map carrier) { + return carrier.keySet(); + } + + @Override + public String get(Map carrier, String key) { + //noinspection ConstantConditions + return carrier.get(key); + } + }; + + private Tracing() {} + + public static void run(String spanName, Runnable runnable) { + serviceTracer().run(spanName, runnable); + } + + public static void run(Span span, Runnable runnable) { + call( + span, + () -> { + runnable.run(); + return null; + }); + } + + /** + * Runs a block of code with a new span - ending the span at the end and recording any exception. + * + * @param spanName name of the new span + */ + public static T call(String spanName, Callable callable) { + return serviceTracer().call(spanName, callable); + } + + public static T call(Span span, Callable callable) { + return call(span, callable, Tracing::setSpanError); + } + + public static T call( + Span span, Callable callable, BiConsumer handleException) { + //noinspection unused + try (Scope scope = span.makeCurrent()) { + return callable.call(); + } catch (Exception e) { + handleException.accept(span, e); + sneakyThrow(e); + return null; + } finally { + span.end(); + } + } + + /** + * @return the tracer to be used in an service + */ + public static ExtendedTracer serviceTracer() { + return ExtendedTracer.create(GlobalOpenTelemetry.getTracer("service")); + } + + public static ExtendedSpanBuilder withSpan(String spanName) { + return serviceTracer().spanBuilder(spanName); + } + + /** + * Marks the current span as error. + * + * @param description what went wrong + */ + public static void setSpanError(String description) { + setSpanError(Span.current(), description); + } + + /** + * Marks the current span as error. + * + * @param exception the exception that caused the error + */ + public static void setSpanError(Throwable exception) { + setSpanError(Span.current(), exception); + } + + /** + * Marks the current span as error. + * + * @param description what went wrong + * @param exception the exception that caused the error + */ + public static void setSpanError(String description, Throwable exception) { + setSpanError(Span.current(), description, exception); + } + + /** + * Marks a span as error. + * + * @param span the span + * @param description what went wrong + */ + public static void setSpanError(Span span, String description) { + span.setStatus(StatusCode.ERROR, description); + } + + /** + * Marks a span as error. + * + * @param span the span + * @param exception the exception that caused the error + */ + public static void setSpanError(Span span, Throwable exception) { + 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 + */ + public static void setSpanError(Span span, String description, Throwable exception) { + span.setStatus(StatusCode.ERROR, description); + span.recordException(exception); + } + + /** + * Injects the current context into a string map, which can then be added to HTTP headers or the + * metadata of an event. + */ + public static Map injectContext() { + Map transport = new HashMap<>(); + //noinspection ConstantConditions + GlobalOpenTelemetry.get() + .getPropagators() + .getTextMapPropagator() + .inject(Context.current(), transport, Map::put); + return transport; + } + + /** + * Extract the context from a string map, which you get from HTTP headers of the metadata of an + * event you're processing. + */ + public static Context extractContext(Map transport) { + Context current = Context.current(); + //noinspection ConstantConditions + if (transport == null) { + return current; + } + // HTTP headers are case-insensitive. As we're using Map, which is case-sensitive, we need to + // normalize all the keys + Map normalizedTransport = + transport.entrySet().stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue)); + return GlobalOpenTelemetry.get() + .getPropagators() + .getTextMapPropagator() + .extract(current, normalizedTransport, TEXT_MAP_GETTER); + } + + /** Sets baggage items which are active in given block. */ + public static T setBaggage(Map baggage, Callable callable) { + BaggageBuilder builder = Baggage.current().toBuilder(); + baggage.forEach(builder::put); + Context context = builder.build().storeInContext(Context.current()); + try (Scope ignore = context.makeCurrent()) { + return callable.call(); + } catch (Throwable e) { + sneakyThrow(e); + return null; + } + } + + /** + * Trace a block of code using a server span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public static T traceServerSpan( + Map transport, SpanBuilder spanBuilder, Callable callable) { + return extractAndRun(SERVER, transport, spanBuilder, callable, Tracing::setSpanError); + } + + /** + * Trace a block of code using a server span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public static T traceServerSpan( + Map transport, + SpanBuilder spanBuilder, + Callable callable, + BiConsumer handleException) { + return extractAndRun(SERVER, transport, spanBuilder, callable, handleException); + } + + /** + * Trace a block of code using a consumer span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public static T traceConsumerSpan( + Map transport, SpanBuilder spanBuilder, Callable callable) { + return extractAndRun(CONSUMER, transport, spanBuilder, callable, Tracing::setSpanError); + } + + /** + * Trace a block of code using a consumer span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public static T traceConsumerSpan( + Map transport, + SpanBuilder spanBuilder, + Callable callable, + BiConsumer handleException) { + return extractAndRun(CONSUMER, transport, spanBuilder, callable, handleException); + } + + private static T extractAndRun( + SpanKind spanKind, + Map transport, + SpanBuilder spanBuilder, + Callable callable, + BiConsumer handleException) { + try (Scope ignore = extractContext(transport).makeCurrent()) { + return call(spanBuilder.setSpanKind(spanKind).startSpan(), callable, handleException); + } + } + + @SuppressWarnings("unchecked") + private static void sneakyThrow(Throwable e) throws E { + throw (E) e; + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index dcd8914b5..4cc198498 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -71,6 +71,7 @@ include(":jfr-connection") include(":jmx-metrics") include(":maven-extension") include(":micrometer-meter-provider") +include(":extended-tracer") include(":noop-api") include(":processors") include(":prometheus-client-bridge") From 5b55f2d233426101109ae1b6e4cbd0c6b4c6674e Mon Sep 17 00:00:00 2001 From: gregor Date: Fri, 14 Jul 2023 18:21:07 +0200 Subject: [PATCH 02/33] add extended tracer module --- .../contrib/tracer/CurrentSpan.java | 40 +++++++++++++ .../opentelemetry/contrib/tracer/Tracing.java | 57 ++++++++----------- 2 files changed, 64 insertions(+), 33 deletions(-) create mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java new file mode 100644 index 000000000..2021a82f7 --- /dev/null +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java @@ -0,0 +1,40 @@ +package io.opentelemetry.contrib.tracer; + +import io.opentelemetry.api.trace.Span; + +/** + * Utility class for the current span. + */ +public final class CurrentSpan { + private CurrentSpan() { + } + + /** + * Marks the current span as error. + * + * @param description what went wrong + * @param exception the exception that caused the error + */ + public static void setSpanError(String description, Throwable exception) { + Tracing.setSpanError(Span.current(), description, exception); + } + + /** + * Marks the current span as error. + * + * @param description what went wrong + */ + public static void setSpanError(String description) { + Tracing.setSpanError(Span.current(), description); + } + + /** + * Marks the current span as error. + * + * @param exception the exception that caused the error + */ + public static void setSpanError(Throwable exception) { + Tracing.setSpanError(Span.current(), exception); + } + +} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index e38c1eaf3..ec3b8ea6f 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -16,26 +16,29 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapGetter; +import javax.annotation.Nullable; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.concurrent.Callable; import java.util.function.BiConsumer; import java.util.stream.Collectors; -public class Tracing { +public final class Tracing { private static final TextMapGetter> TEXT_MAP_GETTER = new TextMapGetter>() { @Override - public Iterable keys(Map carrier) { + public Set keys(Map carrier) { return carrier.keySet(); } @Override - public String get(Map carrier, String key) { + @Nullable + public String get(@Nullable Map carrier, String key) { //noinspection ConstantConditions - return carrier.get(key); + return carrier == null ? null : carrier.get(key); } }; @@ -67,6 +70,7 @@ public static T call(Span span, Callable callable) { return call(span, callable, Tracing::setSpanError); } + @SuppressWarnings("NullAway") public static T call( Span span, Callable callable, BiConsumer handleException) { //noinspection unused @@ -82,42 +86,22 @@ public static T call( } /** - * @return the tracer to be used in an service + * Return the tracer to be used in a service + * + * @return the tracer to be used in a service */ public static ExtendedTracer serviceTracer() { return ExtendedTracer.create(GlobalOpenTelemetry.getTracer("service")); } - public static ExtendedSpanBuilder withSpan(String spanName) { - return serviceTracer().spanBuilder(spanName); - } - - /** - * Marks the current span as error. - * - * @param description what went wrong - */ - public static void setSpanError(String description) { - setSpanError(Span.current(), description); - } - /** - * Marks the current span as error. + * Creates a new span builder with the given span name. * - * @param exception the exception that caused the error - */ - public static void setSpanError(Throwable exception) { - setSpanError(Span.current(), exception); - } - - /** - * Marks the current span as error. - * - * @param description what went wrong - * @param exception the exception that caused the error + * @param spanName the span name + * @return the span builder */ - public static void setSpanError(String description, Throwable exception) { - setSpanError(Span.current(), description, exception); + public static ExtendedSpanBuilder withSpan(String spanName) { + return Tracing.serviceTracer().spanBuilder(spanName); } /** @@ -163,7 +147,13 @@ public static Map injectContext() { GlobalOpenTelemetry.get() .getPropagators() .getTextMapPropagator() - .inject(Context.current(), transport, Map::put); + .inject(Context.current(), transport, + (map, key, value) -> { + if (map != null) { + map.put(key, value); + } + }); + return transport; } @@ -191,6 +181,7 @@ public static Context extractContext(Map transport) { } /** Sets baggage items which are active in given block. */ + @SuppressWarnings("NullAway") public static T setBaggage(Map baggage, Callable callable) { BaggageBuilder builder = Baggage.current().toBuilder(); baggage.forEach(builder::put); From 90632f7e703c484989805f3a5bce42f4764faa8a Mon Sep 17 00:00:00 2001 From: gregor Date: Fri, 14 Jul 2023 18:24:08 +0200 Subject: [PATCH 03/33] add extended tracer module --- .../opentelemetry/contrib/tracer/CurrentSpan.java | 13 +++++++------ .../contrib/tracer/ExtendedSpanBuilder.java | 7 ++++++- .../contrib/tracer/ExtendedTracer.java | 7 ++++++- .../io/opentelemetry/contrib/tracer/Tracing.java | 13 ++++++++++--- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java index 2021a82f7..722994d7b 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java @@ -1,13 +1,15 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.contrib.tracer; import io.opentelemetry.api.trace.Span; -/** - * Utility class for the current span. - */ +/** Utility class for the current span. */ public final class CurrentSpan { - private CurrentSpan() { - } + private CurrentSpan() {} /** * Marks the current span as error. @@ -36,5 +38,4 @@ public static void setSpanError(String description) { public static void setSpanError(Throwable exception) { Tracing.setSpanError(Span.current(), exception); } - } diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java index db05614f6..68fc4e3dd 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java @@ -1,8 +1,13 @@ -package io.opentelemetry.contrib.tracer;/* +/* * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ +package io.opentelemetry.contrib.tracer; /* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java index e799a1a70..df7cb5288 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java @@ -1,8 +1,13 @@ -package io.opentelemetry.contrib.tracer;/* +/* * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ +package io.opentelemetry.contrib.tracer; /* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index ec3b8ea6f..d36c82141 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -1,8 +1,13 @@ -package io.opentelemetry.contrib.tracer;/* +/* * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ +package io.opentelemetry.contrib.tracer; /* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + import static io.opentelemetry.api.trace.SpanKind.CONSUMER; import static io.opentelemetry.api.trace.SpanKind.SERVER; @@ -16,7 +21,6 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapGetter; -import javax.annotation.Nullable; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -24,6 +28,7 @@ import java.util.concurrent.Callable; import java.util.function.BiConsumer; import java.util.stream.Collectors; +import javax.annotation.Nullable; public final class Tracing { @@ -147,7 +152,9 @@ public static Map injectContext() { GlobalOpenTelemetry.get() .getPropagators() .getTextMapPropagator() - .inject(Context.current(), transport, + .inject( + Context.current(), + transport, (map, key, value) -> { if (map != null) { map.put(key, value); From 26f205378f4daf187e74af9810a5c10b29cf22da Mon Sep 17 00:00:00 2001 From: gregor Date: Thu, 27 Jul 2023 16:00:31 +0200 Subject: [PATCH 04/33] limit scope to Tracing utility class add unit tests --- extended-tracer/README.md | 11 + extended-tracer/build.gradle.kts | 6 + .../contrib/tracer/CurrentSpan.java | 41 ---- .../contrib/tracer/ExtendedSpanBuilder.java | 131 ----------- .../contrib/tracer/ExtendedTracer.java | 66 ------ .../opentelemetry/contrib/tracer/Tracing.java | 20 +- .../contrib/tracer/TracingTest.java | 219 ++++++++++++++++++ 7 files changed, 245 insertions(+), 249 deletions(-) create mode 100644 extended-tracer/README.md delete mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java delete mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java delete mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java create mode 100644 extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java diff --git a/extended-tracer/README.md b/extended-tracer/README.md new file mode 100644 index 000000000..37c2b2968 --- /dev/null +++ b/extended-tracer/README.md @@ -0,0 +1,11 @@ +# extended-tracer + +Utility methods to make it easier to use the OpenTelemetry tracer. + +--- + +## Component owners + +- [Gregor Zeitlinger](https://github.com/zeitlinger), Grafana Labs + +Learn more about component owners in [component_owners.yml](../.github/component_owners.yml). diff --git a/extended-tracer/build.gradle.kts b/extended-tracer/build.gradle.kts index 6179cc03e..8b91f75c4 100644 --- a/extended-tracer/build.gradle.kts +++ b/extended-tracer/build.gradle.kts @@ -6,6 +6,12 @@ plugins { description = "Tracing Utilities" otelJava.moduleName.set("io.opentelemetry.contrib.extended-tracer") +otelJava { + minJavaVersionSupported.set(JavaVersion.VERSION_1_8) +} + dependencies { api("io.opentelemetry:opentelemetry-api") + testImplementation("io.opentelemetry:opentelemetry-sdk-testing") + testImplementation("io.opentelemetry:opentelemetry-semconv") } diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java deleted file mode 100644 index 722994d7b..000000000 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/CurrentSpan.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.tracer; - -import io.opentelemetry.api.trace.Span; - -/** Utility class for the current span. */ -public final class CurrentSpan { - private CurrentSpan() {} - - /** - * Marks the current span as error. - * - * @param description what went wrong - * @param exception the exception that caused the error - */ - public static void setSpanError(String description, Throwable exception) { - Tracing.setSpanError(Span.current(), description, exception); - } - - /** - * Marks the current span as error. - * - * @param description what went wrong - */ - public static void setSpanError(String description) { - Tracing.setSpanError(Span.current(), description); - } - - /** - * Marks the current span as error. - * - * @param exception the exception that caused the error - */ - public static void setSpanError(Throwable exception) { - Tracing.setSpanError(Span.current(), exception); - } -} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java deleted file mode 100644 index 68fc4e3dd..000000000 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedSpanBuilder.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.tracer; /* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import java.time.Instant; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; - -public class ExtendedSpanBuilder implements SpanBuilder { - - private final SpanBuilder delegate; - - ExtendedSpanBuilder(SpanBuilder delegate) { - this.delegate = delegate; - } - - /** Run the provided {@link Runnable} and wrap with a {@link Span} with the provided name. */ - public void run(Runnable runnable) { - Tracing.run(startSpan(), runnable); - } - - /** Call the provided {@link Callable} and wrap with a {@link Span} with the provided name. */ - public T call(Callable callable) { - return Tracing.call(startSpan(), callable); - } - - /** - * Trace a block of code using a server span. - * - *

The span context will be extracted from the transport, which you usually get - * from HTTP headers of the metadata of an event you're processing. - */ - public T traceServerSpan(Map transport, Callable callable) { - return Tracing.traceServerSpan(transport, this, callable); - } - - /** - * Trace a block of code using a consumer span. - * - *

The span context will be extracted from the transport, which you usually get - * from HTTP headers of the metadata of an event you're processing. - */ - public T traceConsumerSpan( - Map transport, SpanBuilder spanBuilder, Callable callable) { - return Tracing.traceConsumerSpan(transport, this, callable); - } - - @Override - public SpanBuilder setParent(Context context) { - return delegate.setParent(context); - } - - @Override - public SpanBuilder setNoParent() { - return delegate.setNoParent(); - } - - @Override - public SpanBuilder addLink(SpanContext spanContext) { - return delegate.addLink(spanContext); - } - - @Override - public SpanBuilder addLink(SpanContext spanContext, Attributes attributes) { - return delegate.addLink(spanContext, attributes); - } - - @Override - public SpanBuilder setAttribute(String key, String value) { - return delegate.setAttribute(key, value); - } - - @Override - public SpanBuilder setAttribute(String key, long value) { - return delegate.setAttribute(key, value); - } - - @Override - public SpanBuilder setAttribute(String key, double value) { - return delegate.setAttribute(key, value); - } - - @Override - public SpanBuilder setAttribute(String key, boolean value) { - return delegate.setAttribute(key, value); - } - - @Override - public SpanBuilder setAttribute(AttributeKey key, T value) { - return delegate.setAttribute(key, value); - } - - @Override - public SpanBuilder setAllAttributes(Attributes attributes) { - return delegate.setAllAttributes(attributes); - } - - @Override - public SpanBuilder setSpanKind(SpanKind spanKind) { - return delegate.setSpanKind(spanKind); - } - - @Override - public SpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) { - return delegate.setStartTimestamp(startTimestamp, unit); - } - - @Override - public SpanBuilder setStartTimestamp(Instant startTimestamp) { - return delegate.setStartTimestamp(startTimestamp); - } - - @Override - public Span startSpan() { - return delegate.startSpan(); - } -} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java deleted file mode 100644 index df7cb5288..000000000 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ExtendedTracer.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.tracer; /* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.context.Context; -import java.util.Map; -import java.util.concurrent.Callable; - -/** Provides easy mechanisms for wrapping standard Java constructs with an OpenTelemetry Span. */ -public final class ExtendedTracer implements Tracer { - - private final Tracer delegate; - - /** Create a new {@link ExtendedTracer} that wraps the provided Tracer. */ - public static ExtendedTracer create(Tracer delegate) { - return new ExtendedTracer(delegate); - } - - private ExtendedTracer(Tracer delegate) { - this.delegate = delegate; - } - - /** Run the provided {@link Runnable} and wrap with a {@link Span} with the provided name. */ - public void run(String spanName, Runnable runnable) { - spanBuilder(spanName).run(runnable); - } - - /** Call the provided {@link Callable} and wrap with a {@link Span} with the provided name. */ - public T call(String spanName, Callable callable) { - return spanBuilder(spanName).call(callable); - } - - /** - * Injects the current context into a string map, which can then be added to HTTP headers or the - * metadata of an event. - */ - public Map injectContext() { - return Tracing.injectContext(); - } - - /** - * Extract the context from a string map, which you get from HTTP headers of the metadata of an - * event you're processing. - */ - public static Context extractContext(Map transport) { - return Tracing.extractContext(transport); - } - - /** Sets baggage items which are active in given block. */ - public static T setBaggage(Map baggage, Callable callable) { - return Tracing.setBaggage(baggage, callable); - } - - @Override - public ExtendedSpanBuilder spanBuilder(String spanName) { - return new ExtendedSpanBuilder(delegate.spanBuilder(spanName)); - } -} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index d36c82141..c1cd4f965 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -3,10 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.tracer; /* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ +package io.opentelemetry.contrib.tracer; import static io.opentelemetry.api.trace.SpanKind.CONSUMER; import static io.opentelemetry.api.trace.SpanKind.SERVER; @@ -18,6 +15,7 @@ import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapGetter; @@ -50,7 +48,7 @@ public String get(@Nullable Map carrier, String key) { private Tracing() {} public static void run(String spanName, Runnable runnable) { - serviceTracer().run(spanName, runnable); + run(serviceTracer().spanBuilder(spanName).startSpan(), runnable); } public static void run(Span span, Runnable runnable) { @@ -68,7 +66,7 @@ public static void run(Span span, Runnable runnable) { * @param spanName name of the new span */ public static T call(String spanName, Callable callable) { - return serviceTracer().call(spanName, callable); + return call(serviceTracer().spanBuilder(spanName).startSpan(), callable); } public static T call(Span span, Callable callable) { @@ -95,8 +93,8 @@ public static T call( * * @return the tracer to be used in a service */ - public static ExtendedTracer serviceTracer() { - return ExtendedTracer.create(GlobalOpenTelemetry.getTracer("service")); + public static Tracer serviceTracer() { + return GlobalOpenTelemetry.getTracer("service"); } /** @@ -105,7 +103,7 @@ public static ExtendedTracer serviceTracer() { * @param spanName the span name * @return the span builder */ - public static ExtendedSpanBuilder withSpan(String spanName) { + public static SpanBuilder withSpan(String spanName) { return Tracing.serviceTracer().spanBuilder(spanName); } @@ -146,7 +144,7 @@ public static void setSpanError(Span span, String description, Throwable excepti * Injects the current context into a string map, which can then be added to HTTP headers or the * metadata of an event. */ - public static Map injectContext() { + public static Map getPropagationHeaders() { Map transport = new HashMap<>(); //noinspection ConstantConditions GlobalOpenTelemetry.get() @@ -189,7 +187,7 @@ public static Context extractContext(Map transport) { /** Sets baggage items which are active in given block. */ @SuppressWarnings("NullAway") - public static T setBaggage(Map baggage, Callable callable) { + public static T callWithBaggage(Map baggage, Callable callable) { BaggageBuilder builder = Baggage.current().toBuilder(); baggage.forEach(builder::put); Context context = builder.build().storeInContext(Context.current()); diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java new file mode 100644 index 000000000..2d55c475a --- /dev/null +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -0,0 +1,219 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.tracer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatException; +import static org.junit.jupiter.api.Named.named; + +import com.google.errorprone.annotations.Keep; +import io.opentelemetry.api.baggage.Baggage; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.stream.Stream; +import org.assertj.core.api.AbstractCharSequenceAssert; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class TracingTest { + + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + + @Test + void propagation() { + Tracing.run( + "parent", + () -> { + Map propagationHeaders = Tracing.getPropagationHeaders(); + assertThat(propagationHeaders).hasSize(1).containsKey("traceparent"); + + Tracing.traceServerSpan(propagationHeaders, Tracing.withSpan("child"), () -> null); + }); + + otelTesting + .assertTraces() + .hasSize(1) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + SpanDataAssert::hasNoParent, span -> span.hasParent(trace.getSpan(0)))); + } + + @Test + void callWithBaggage() { + String value = + Tracing.call( + "parent", + () -> + Tracing.callWithBaggage( + Collections.singletonMap("key", "value"), + () -> Baggage.current().getEntryValue("key"))); + + assertThat(value).isEqualTo("value"); + } + + private static class ExtractAndRunParameter { + private final Consumer> extractAndRun; + private final SpanKind wantKind; + private final StatusData wantStatus; + + private ExtractAndRunParameter( + Consumer> extractAndRun, SpanKind wantKind, StatusData wantStatus) { + this.extractAndRun = extractAndRun; + this.wantKind = wantKind; + this.wantStatus = wantStatus; + } + } + + @Keep + private static Stream extractAndRun() { + BiConsumer ignoreException = + (span, throwable) -> { + // ignore + }; + return Stream.of( + Arguments.of( + named( + "server", + new ExtractAndRunParameter( + c -> + Tracing.traceServerSpan( + Collections.emptyMap(), Tracing.withSpan("span"), c), + io.opentelemetry.api.trace.SpanKind.SERVER, + io.opentelemetry.sdk.trace.data.StatusData.error()))), + Arguments.of( + named( + "server - ignore exception", + new ExtractAndRunParameter( + c -> + Tracing.traceServerSpan( + Collections.emptyMap(), Tracing.withSpan("span"), c, ignoreException), + io.opentelemetry.api.trace.SpanKind.SERVER, + io.opentelemetry.sdk.trace.data.StatusData.unset()))), + Arguments.of( + named( + "consumer", + new ExtractAndRunParameter( + c -> + Tracing.traceConsumerSpan( + Collections.emptyMap(), Tracing.withSpan("span"), c), + io.opentelemetry.api.trace.SpanKind.CONSUMER, + io.opentelemetry.sdk.trace.data.StatusData.error()))), + Arguments.of( + named( + "consumer - ignore exception", + new ExtractAndRunParameter( + c -> + Tracing.traceConsumerSpan( + Collections.emptyMap(), Tracing.withSpan("span"), c, ignoreException), + io.opentelemetry.api.trace.SpanKind.CONSUMER, + io.opentelemetry.sdk.trace.data.StatusData.unset())))); + } + + @ParameterizedTest + @MethodSource + void extractAndRun(ExtractAndRunParameter parameter) { + assertThatException() + .isThrownBy( + () -> + parameter.extractAndRun.accept( + () -> { + throw new RuntimeException("ex"); + })); + + otelTesting + .assertTraces() + .hasSize(1) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasKind(parameter.wantKind).hasStatus(parameter.wantStatus))); + } + + private static class SetSpanErrorParameter { + private final Consumer setError; + private final String wantDescription; + private final Throwable wantException; + + private SetSpanErrorParameter( + Consumer setError, String wantDescription, Throwable wantException) { + this.setError = setError; + this.wantDescription = wantDescription; + this.wantException = wantException; + } + } + + @Keep + private static Stream setSpanError() { + RuntimeException exception = new RuntimeException("ex"); + return Stream.of( + Arguments.of( + named( + "with description", + new SetSpanErrorParameter(s -> Tracing.setSpanError(s, "error"), "error", null))), + Arguments.of( + named( + "with exception", + new SetSpanErrorParameter( + s -> Tracing.setSpanError(s, exception), null, exception))), + Arguments.of( + named( + "with exception and description", + new SetSpanErrorParameter( + s -> Tracing.setSpanError(s, "error", exception), "error", exception)))); + } + + @ParameterizedTest + @MethodSource + void setSpanError(SetSpanErrorParameter parameter) { + Tracing.run("parent", () -> parameter.setError.accept(Span.current())); + + otelTesting + .assertTraces() + .hasSize(1) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> { + SpanDataAssert spanDataAssert = + span.hasStatus( + StatusData.create(StatusCode.ERROR, parameter.wantDescription)); + if (parameter.wantException != null) { + spanDataAssert.hasEventsSatisfyingExactly( + event -> + event.hasAttributesSatisfyingExactly( + OpenTelemetryAssertions.satisfies( + SemanticAttributes.EXCEPTION_TYPE, + s -> + s.isEqualTo( + parameter.wantException.getClass().getName())), + OpenTelemetryAssertions.satisfies( + SemanticAttributes.EXCEPTION_MESSAGE, + AbstractCharSequenceAssert::isNotBlank), + OpenTelemetryAssertions.satisfies( + SemanticAttributes.EXCEPTION_STACKTRACE, + AbstractCharSequenceAssert::isNotBlank))); + } else { + spanDataAssert.hasTotalRecordedEvents(0); + } + })); + } +} From c3a3fbaf63f5bd95aaaaa53e0aaf4e52fc78f485 Mon Sep 17 00:00:00 2001 From: gregor Date: Mon, 7 Aug 2023 10:58:51 +0200 Subject: [PATCH 05/33] make it clear that passed in span is ended --- .../io/opentelemetry/contrib/tracer/Tracing.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index c1cd4f965..cd7530145 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -48,11 +48,11 @@ public String get(@Nullable Map carrier, String key) { private Tracing() {} public static void run(String spanName, Runnable runnable) { - run(serviceTracer().spanBuilder(spanName).startSpan(), runnable); + runAndEndSpan(serviceTracer().spanBuilder(spanName).startSpan(), runnable); } - public static void run(Span span, Runnable runnable) { - call( + public static void runAndEndSpan(Span span, Runnable runnable) { + callAndEndSpan( span, () -> { runnable.run(); @@ -66,15 +66,15 @@ public static void run(Span span, Runnable runnable) { * @param spanName name of the new span */ public static T call(String spanName, Callable callable) { - return call(serviceTracer().spanBuilder(spanName).startSpan(), callable); + return callAndEndSpan(serviceTracer().spanBuilder(spanName).startSpan(), callable); } - public static T call(Span span, Callable callable) { - return call(span, callable, Tracing::setSpanError); + public static T callAndEndSpan(Span span, Callable callable) { + return callAndEndSpan(span, callable, Tracing::setSpanError); } @SuppressWarnings("NullAway") - public static T call( + public static T callAndEndSpan( Span span, Callable callable, BiConsumer handleException) { //noinspection unused try (Scope scope = span.makeCurrent()) { @@ -256,7 +256,7 @@ private static T extractAndRun( Callable callable, BiConsumer handleException) { try (Scope ignore = extractContext(transport).makeCurrent()) { - return call(spanBuilder.setSpanKind(spanKind).startSpan(), callable, handleException); + return callAndEndSpan(spanBuilder.setSpanKind(spanKind).startSpan(), callable, handleException); } } From 0ed2bd6e684c3c6ddc5c1d2d85f8d635cc15b4b7 Mon Sep 17 00:00:00 2001 From: gregor Date: Mon, 7 Aug 2023 11:32:21 +0200 Subject: [PATCH 06/33] extract GlobalTracing to make it clear where the global otel instance is used --- .../contrib/tracer/GlobalTracing.java | 119 ++++++++++++++++++ .../opentelemetry/contrib/tracer/Tracing.java | 66 +++++----- ...racingTest.java => GlobalTracingTest.java} | 41 +++--- 3 files changed, 176 insertions(+), 50 deletions(-) create mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java rename extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/{TracingTest.java => GlobalTracingTest.java} (84%) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java new file mode 100644 index 000000000..24265d54e --- /dev/null +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java @@ -0,0 +1,119 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.tracer; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.function.BiConsumer; + +public class GlobalTracing { + private GlobalTracing() {} + + /** + * Return the tracer to be used in a service + * + * @return the tracer to be used in a service + */ + public static Tracer serviceTracer() { + return GlobalOpenTelemetry.getTracer("service"); + } + + public static void run(String spanName, Runnable runnable) { + Tracing.run(serviceTracer(), spanName, runnable); + } + + /** + * Runs a block of code with a new span - ending the span at the end and recording any exception. + * + * @param spanName name of the new span + */ + public static T call(String spanName, Callable callable) { + return Tracing.call(serviceTracer(), spanName, callable); + } + + /** + * Creates a new span builder with the given span name. + * + * @param spanName the span name + * @return the span builder + */ + public static SpanBuilder withSpan(String spanName) { + return serviceTracer().spanBuilder(spanName); + } + + /** + * Injects the current context into a string map, which can then be added to HTTP headers or the + * metadata of an event. + */ + public static Map getPropagationHeaders() { + return Tracing.getPropagationHeaders(GlobalOpenTelemetry.get()); + } + + /** + * Extract the context from a string map, which you get from HTTP headers of the metadata of an + * event you're processing. + */ + public static Context extractContext(Map transport) { + return Tracing.extractContext(GlobalOpenTelemetry.get(), transport); + } + + /** + * Trace a block of code using a server span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public static T traceServerSpan( + Map transport, SpanBuilder spanBuilder, Callable callable) { + return Tracing.traceServerSpan(GlobalOpenTelemetry.get(), transport, spanBuilder, callable); + } + + /** + * Trace a block of code using a server span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public static T traceServerSpan( + Map transport, + SpanBuilder spanBuilder, + Callable callable, + BiConsumer handleException) { + return Tracing.traceServerSpan( + GlobalOpenTelemetry.get(), transport, spanBuilder, callable, handleException); + } + + /** + * Trace a block of code using a consumer span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public static T traceConsumerSpan( + Map transport, SpanBuilder spanBuilder, Callable callable) { + return Tracing.traceConsumerSpan(GlobalOpenTelemetry.get(), transport, spanBuilder, callable); + } + + /** + * Trace a block of code using a consumer span. + * + *

The span context will be extracted from the transport, which you usually get + * from HTTP headers of the metadata of an event you're processing. + */ + public static T traceConsumerSpan( + Map transport, + SpanBuilder spanBuilder, + Callable callable, + BiConsumer handleException) { + return Tracing.traceConsumerSpan( + GlobalOpenTelemetry.get(), transport, spanBuilder, callable, handleException); + } +} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index cd7530145..c05908129 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -8,7 +8,7 @@ import static io.opentelemetry.api.trace.SpanKind.CONSUMER; import static io.opentelemetry.api.trace.SpanKind.SERVER; -import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.api.baggage.BaggageBuilder; import io.opentelemetry.api.trace.Span; @@ -47,8 +47,8 @@ public String get(@Nullable Map carrier, String key) { private Tracing() {} - public static void run(String spanName, Runnable runnable) { - runAndEndSpan(serviceTracer().spanBuilder(spanName).startSpan(), runnable); + public static void run(Tracer tracer, String spanName, Runnable runnable) { + runAndEndSpan(tracer.spanBuilder(spanName).startSpan(), runnable); } public static void runAndEndSpan(Span span, Runnable runnable) { @@ -65,8 +65,8 @@ public static void runAndEndSpan(Span span, Runnable runnable) { * * @param spanName name of the new span */ - public static T call(String spanName, Callable callable) { - return callAndEndSpan(serviceTracer().spanBuilder(spanName).startSpan(), callable); + public static T call(Tracer tracer, String spanName, Callable callable) { + return callAndEndSpan(tracer.spanBuilder(spanName).startSpan(), callable); } public static T callAndEndSpan(Span span, Callable callable) { @@ -88,25 +88,6 @@ public static T callAndEndSpan( } } - /** - * Return the tracer to be used in a service - * - * @return the tracer to be used in a service - */ - public static Tracer serviceTracer() { - return GlobalOpenTelemetry.getTracer("service"); - } - - /** - * Creates a new span builder with the given span name. - * - * @param spanName the span name - * @return the span builder - */ - public static SpanBuilder withSpan(String spanName) { - return Tracing.serviceTracer().spanBuilder(spanName); - } - /** * Marks a span as error. * @@ -144,10 +125,10 @@ public static void setSpanError(Span span, String description, Throwable excepti * Injects the current context into a string map, which can then be added to HTTP headers or the * metadata of an event. */ - public static Map getPropagationHeaders() { + public static Map getPropagationHeaders(OpenTelemetry openTelemetry) { Map transport = new HashMap<>(); //noinspection ConstantConditions - GlobalOpenTelemetry.get() + openTelemetry .getPropagators() .getTextMapPropagator() .inject( @@ -166,7 +147,7 @@ public static Map getPropagationHeaders() { * Extract the context from a string map, which you get from HTTP headers of the metadata of an * event you're processing. */ - public static Context extractContext(Map transport) { + public static Context extractContext(OpenTelemetry openTelemetry, Map transport) { Context current = Context.current(); //noinspection ConstantConditions if (transport == null) { @@ -179,7 +160,7 @@ public static Context extractContext(Map transport) { .collect( Collectors.toMap( entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue)); - return GlobalOpenTelemetry.get() + return openTelemetry .getPropagators() .getTextMapPropagator() .extract(current, normalizedTransport, TEXT_MAP_GETTER); @@ -206,8 +187,12 @@ public static T callWithBaggage(Map baggage, Callable cal * from HTTP headers of the metadata of an event you're processing. */ public static T traceServerSpan( - Map transport, SpanBuilder spanBuilder, Callable callable) { - return extractAndRun(SERVER, transport, spanBuilder, callable, Tracing::setSpanError); + OpenTelemetry openTelemetry, + Map transport, + SpanBuilder spanBuilder, + Callable callable) { + return extractAndRun( + openTelemetry, SERVER, transport, spanBuilder, callable, Tracing::setSpanError); } /** @@ -217,11 +202,12 @@ public static T traceServerSpan( * from HTTP headers of the metadata of an event you're processing. */ public static T traceServerSpan( + OpenTelemetry openTelemetry, Map transport, SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { - return extractAndRun(SERVER, transport, spanBuilder, callable, handleException); + return extractAndRun(openTelemetry, SERVER, transport, spanBuilder, callable, handleException); } /** @@ -231,8 +217,12 @@ public static T traceServerSpan( * from HTTP headers of the metadata of an event you're processing. */ public static T traceConsumerSpan( - Map transport, SpanBuilder spanBuilder, Callable callable) { - return extractAndRun(CONSUMER, transport, spanBuilder, callable, Tracing::setSpanError); + OpenTelemetry openTelemetry, + Map transport, + SpanBuilder spanBuilder, + Callable callable) { + return extractAndRun( + openTelemetry, CONSUMER, transport, spanBuilder, callable, Tracing::setSpanError); } /** @@ -242,21 +232,25 @@ public static T traceConsumerSpan( * from HTTP headers of the metadata of an event you're processing. */ public static T traceConsumerSpan( + OpenTelemetry openTelemetry, Map transport, SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { - return extractAndRun(CONSUMER, transport, spanBuilder, callable, handleException); + return extractAndRun( + openTelemetry, CONSUMER, transport, spanBuilder, callable, handleException); } private static T extractAndRun( + OpenTelemetry openTelemetry, SpanKind spanKind, Map transport, SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { - try (Scope ignore = extractContext(transport).makeCurrent()) { - return callAndEndSpan(spanBuilder.setSpanKind(spanKind).startSpan(), callable, handleException); + try (Scope ignore = extractContext(openTelemetry, transport).makeCurrent()) { + return callAndEndSpan( + spanBuilder.setSpanKind(spanKind).startSpan(), callable, handleException); } } diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java similarity index 84% rename from extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java rename to extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java index 2d55c475a..d1234f1ad 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java @@ -32,20 +32,27 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -public class TracingTest { +public class GlobalTracingTest { @RegisterExtension static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); @Test void propagation() { - Tracing.run( + GlobalTracing.run( "parent", () -> { - Map propagationHeaders = Tracing.getPropagationHeaders(); + Map propagationHeaders = GlobalTracing.getPropagationHeaders(); assertThat(propagationHeaders).hasSize(1).containsKey("traceparent"); - Tracing.traceServerSpan(propagationHeaders, Tracing.withSpan("child"), () -> null); + assertThat( + Span.fromContext(GlobalTracing.extractContext(propagationHeaders)) + .getSpanContext() + .getSpanId()) + .isEqualTo(Span.current().getSpanContext().getSpanId()); + + GlobalTracing.traceServerSpan( + propagationHeaders, GlobalTracing.withSpan("child"), () -> null); }); otelTesting @@ -60,7 +67,7 @@ void propagation() { @Test void callWithBaggage() { String value = - Tracing.call( + GlobalTracing.call( "parent", () -> Tracing.callWithBaggage( @@ -95,8 +102,8 @@ private static Stream extractAndRun() { "server", new ExtractAndRunParameter( c -> - Tracing.traceServerSpan( - Collections.emptyMap(), Tracing.withSpan("span"), c), + GlobalTracing.traceServerSpan( + Collections.emptyMap(), GlobalTracing.withSpan("span"), c), io.opentelemetry.api.trace.SpanKind.SERVER, io.opentelemetry.sdk.trace.data.StatusData.error()))), Arguments.of( @@ -104,8 +111,11 @@ private static Stream extractAndRun() { "server - ignore exception", new ExtractAndRunParameter( c -> - Tracing.traceServerSpan( - Collections.emptyMap(), Tracing.withSpan("span"), c, ignoreException), + GlobalTracing.traceServerSpan( + Collections.emptyMap(), + GlobalTracing.withSpan("span"), + c, + ignoreException), io.opentelemetry.api.trace.SpanKind.SERVER, io.opentelemetry.sdk.trace.data.StatusData.unset()))), Arguments.of( @@ -113,8 +123,8 @@ private static Stream extractAndRun() { "consumer", new ExtractAndRunParameter( c -> - Tracing.traceConsumerSpan( - Collections.emptyMap(), Tracing.withSpan("span"), c), + GlobalTracing.traceConsumerSpan( + Collections.emptyMap(), GlobalTracing.withSpan("span"), c), io.opentelemetry.api.trace.SpanKind.CONSUMER, io.opentelemetry.sdk.trace.data.StatusData.error()))), Arguments.of( @@ -122,8 +132,11 @@ private static Stream extractAndRun() { "consumer - ignore exception", new ExtractAndRunParameter( c -> - Tracing.traceConsumerSpan( - Collections.emptyMap(), Tracing.withSpan("span"), c, ignoreException), + GlobalTracing.traceConsumerSpan( + Collections.emptyMap(), + GlobalTracing.withSpan("span"), + c, + ignoreException), io.opentelemetry.api.trace.SpanKind.CONSUMER, io.opentelemetry.sdk.trace.data.StatusData.unset())))); } @@ -184,7 +197,7 @@ private static Stream setSpanError() { @ParameterizedTest @MethodSource void setSpanError(SetSpanErrorParameter parameter) { - Tracing.run("parent", () -> parameter.setError.accept(Span.current())); + GlobalTracing.run("parent", () -> parameter.setError.accept(Span.current())); otelTesting .assertTraces() From dd1706188796a4eb706e372664264d311b711076 Mon Sep 17 00:00:00 2001 From: gregor Date: Tue, 8 Aug 2023 08:17:43 +0200 Subject: [PATCH 07/33] make OpenTelemetry a field in Tracing --- .../contrib/tracer/GlobalTracing.java | 30 ++++++--- .../opentelemetry/contrib/tracer/Tracing.java | 65 ++++++++----------- .../contrib/tracer/GlobalTracingTest.java | 11 ++-- 3 files changed, 55 insertions(+), 51 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java index 24265d54e..ed0ede821 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java @@ -14,6 +14,14 @@ import java.util.concurrent.Callable; import java.util.function.BiConsumer; +/** + * Tracing utility methods that rely on the {@link io.opentelemetry.api.GlobalOpenTelemetry} + * instance. + * + *

If the application is not running in javaagent, the first call to any of the methods in this + * class may trigger the initialization of the {@link io.opentelemetry.api.GlobalOpenTelemetry} * + * instance. + */ public class GlobalTracing { private GlobalTracing() {} @@ -26,8 +34,12 @@ public static Tracer serviceTracer() { return GlobalOpenTelemetry.getTracer("service"); } + private static Tracing tracing() { + return new Tracing(GlobalOpenTelemetry.get()); + } + public static void run(String spanName, Runnable runnable) { - Tracing.run(serviceTracer(), spanName, runnable); + tracing().run(serviceTracer(), spanName, runnable); } /** @@ -36,7 +48,7 @@ public static void run(String spanName, Runnable runnable) { * @param spanName name of the new span */ public static T call(String spanName, Callable callable) { - return Tracing.call(serviceTracer(), spanName, callable); + return tracing().call(serviceTracer(), spanName, callable); } /** @@ -54,7 +66,7 @@ public static SpanBuilder withSpan(String spanName) { * metadata of an event. */ public static Map getPropagationHeaders() { - return Tracing.getPropagationHeaders(GlobalOpenTelemetry.get()); + return tracing().getPropagationHeaders(); } /** @@ -62,7 +74,7 @@ public static Map getPropagationHeaders() { * event you're processing. */ public static Context extractContext(Map transport) { - return Tracing.extractContext(GlobalOpenTelemetry.get(), transport); + return tracing().extractContext(transport); } /** @@ -73,7 +85,7 @@ public static Context extractContext(Map transport) { */ public static T traceServerSpan( Map transport, SpanBuilder spanBuilder, Callable callable) { - return Tracing.traceServerSpan(GlobalOpenTelemetry.get(), transport, spanBuilder, callable); + return tracing().traceServerSpan(transport, spanBuilder, callable); } /** @@ -87,8 +99,7 @@ public static T traceServerSpan( SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { - return Tracing.traceServerSpan( - GlobalOpenTelemetry.get(), transport, spanBuilder, callable, handleException); + return tracing().traceServerSpan(transport, spanBuilder, callable, handleException); } /** @@ -99,7 +110,7 @@ public static T traceServerSpan( */ public static T traceConsumerSpan( Map transport, SpanBuilder spanBuilder, Callable callable) { - return Tracing.traceConsumerSpan(GlobalOpenTelemetry.get(), transport, spanBuilder, callable); + return tracing().traceConsumerSpan(transport, spanBuilder, callable); } /** @@ -113,7 +124,6 @@ public static T traceConsumerSpan( SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { - return Tracing.traceConsumerSpan( - GlobalOpenTelemetry.get(), transport, spanBuilder, callable, handleException); + return tracing().traceConsumerSpan(transport, spanBuilder, callable, handleException); } } diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index c05908129..4bad68967 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -44,14 +44,17 @@ public String get(@Nullable Map carrier, String key) { return carrier == null ? null : carrier.get(key); } }; + private final OpenTelemetry openTelemetry; - private Tracing() {} + public Tracing(OpenTelemetry openTelemetry) { + this.openTelemetry = openTelemetry; + } - public static void run(Tracer tracer, String spanName, Runnable runnable) { + public void run(Tracer tracer, String spanName, Runnable runnable) { runAndEndSpan(tracer.spanBuilder(spanName).startSpan(), runnable); } - public static void runAndEndSpan(Span span, Runnable runnable) { + public void runAndEndSpan(Span span, Runnable runnable) { callAndEndSpan( span, () -> { @@ -65,16 +68,16 @@ public static void runAndEndSpan(Span span, Runnable runnable) { * * @param spanName name of the new span */ - public static T call(Tracer tracer, String spanName, Callable callable) { + public T call(Tracer tracer, String spanName, Callable callable) { return callAndEndSpan(tracer.spanBuilder(spanName).startSpan(), callable); } - public static T callAndEndSpan(Span span, Callable callable) { - return callAndEndSpan(span, callable, Tracing::setSpanError); + public T callAndEndSpan(Span span, Callable callable) { + return callAndEndSpan(span, callable, this::setSpanError); } @SuppressWarnings("NullAway") - public static T callAndEndSpan( + public T callAndEndSpan( Span span, Callable callable, BiConsumer handleException) { //noinspection unused try (Scope scope = span.makeCurrent()) { @@ -94,7 +97,7 @@ public static T callAndEndSpan( * @param span the span * @param description what went wrong */ - public static void setSpanError(Span span, String description) { + public void setSpanError(Span span, String description) { span.setStatus(StatusCode.ERROR, description); } @@ -104,7 +107,7 @@ public static void setSpanError(Span span, String description) { * @param span the span * @param exception the exception that caused the error */ - public static void setSpanError(Span span, Throwable exception) { + public void setSpanError(Span span, Throwable exception) { span.setStatus(StatusCode.ERROR); span.recordException(exception); } @@ -116,7 +119,7 @@ public static void setSpanError(Span span, Throwable exception) { * @param description what went wrong * @param exception the exception that caused the error */ - public static void setSpanError(Span span, String description, Throwable exception) { + public void setSpanError(Span span, String description, Throwable exception) { span.setStatus(StatusCode.ERROR, description); span.recordException(exception); } @@ -125,7 +128,7 @@ public static void setSpanError(Span span, String description, Throwable excepti * Injects the current context into a string map, which can then be added to HTTP headers or the * metadata of an event. */ - public static Map getPropagationHeaders(OpenTelemetry openTelemetry) { + public Map getPropagationHeaders() { Map transport = new HashMap<>(); //noinspection ConstantConditions openTelemetry @@ -147,7 +150,7 @@ public static Map getPropagationHeaders(OpenTelemetry openTeleme * Extract the context from a string map, which you get from HTTP headers of the metadata of an * event you're processing. */ - public static Context extractContext(OpenTelemetry openTelemetry, Map transport) { + public Context extractContext(Map transport) { Context current = Context.current(); //noinspection ConstantConditions if (transport == null) { @@ -168,7 +171,7 @@ public static Context extractContext(OpenTelemetry openTelemetry, Map T callWithBaggage(Map baggage, Callable callable) { + public T callWithBaggage(Map baggage, Callable callable) { BaggageBuilder builder = Baggage.current().toBuilder(); baggage.forEach(builder::put); Context context = builder.build().storeInContext(Context.current()); @@ -186,13 +189,9 @@ public static T callWithBaggage(Map baggage, Callable cal *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. */ - public static T traceServerSpan( - OpenTelemetry openTelemetry, - Map transport, - SpanBuilder spanBuilder, - Callable callable) { - return extractAndRun( - openTelemetry, SERVER, transport, spanBuilder, callable, Tracing::setSpanError); + public T traceServerSpan( + Map transport, SpanBuilder spanBuilder, Callable callable) { + return extractAndRun(SERVER, transport, spanBuilder, callable, this::setSpanError); } /** @@ -201,13 +200,12 @@ public static T traceServerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. */ - public static T traceServerSpan( - OpenTelemetry openTelemetry, + public T traceServerSpan( Map transport, SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { - return extractAndRun(openTelemetry, SERVER, transport, spanBuilder, callable, handleException); + return extractAndRun(SERVER, transport, spanBuilder, callable, handleException); } /** @@ -216,13 +214,9 @@ public static T traceServerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. */ - public static T traceConsumerSpan( - OpenTelemetry openTelemetry, - Map transport, - SpanBuilder spanBuilder, - Callable callable) { - return extractAndRun( - openTelemetry, CONSUMER, transport, spanBuilder, callable, Tracing::setSpanError); + public T traceConsumerSpan( + Map transport, SpanBuilder spanBuilder, Callable callable) { + return extractAndRun(CONSUMER, transport, spanBuilder, callable, this::setSpanError); } /** @@ -231,24 +225,21 @@ public static T traceConsumerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. */ - public static T traceConsumerSpan( - OpenTelemetry openTelemetry, + public T traceConsumerSpan( Map transport, SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { - return extractAndRun( - openTelemetry, CONSUMER, transport, spanBuilder, callable, handleException); + return extractAndRun(CONSUMER, transport, spanBuilder, callable, handleException); } - private static T extractAndRun( - OpenTelemetry openTelemetry, + private T extractAndRun( SpanKind spanKind, Map transport, SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { - try (Scope ignore = extractContext(openTelemetry, transport).makeCurrent()) { + try (Scope ignore = extractContext(transport).makeCurrent()) { return callAndEndSpan( spanBuilder.setSpanKind(spanKind).startSpan(), callable, handleException); } diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java index d1234f1ad..9d05692cd 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java @@ -37,6 +37,8 @@ public class GlobalTracingTest { @RegisterExtension static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + private final Tracing tracing = new Tracing(otelTesting.getOpenTelemetry()); + @Test void propagation() { GlobalTracing.run( @@ -70,7 +72,7 @@ void callWithBaggage() { GlobalTracing.call( "parent", () -> - Tracing.callWithBaggage( + tracing.callWithBaggage( Collections.singletonMap("key", "value"), () -> Baggage.current().getEntryValue("key"))); @@ -176,22 +178,23 @@ private SetSpanErrorParameter( @Keep private static Stream setSpanError() { + Tracing tracing = new Tracing(otelTesting.getOpenTelemetry()); RuntimeException exception = new RuntimeException("ex"); return Stream.of( Arguments.of( named( "with description", - new SetSpanErrorParameter(s -> Tracing.setSpanError(s, "error"), "error", null))), + new SetSpanErrorParameter(s -> tracing.setSpanError(s, "error"), "error", null))), Arguments.of( named( "with exception", new SetSpanErrorParameter( - s -> Tracing.setSpanError(s, exception), null, exception))), + s -> tracing.setSpanError(s, exception), null, exception))), Arguments.of( named( "with exception and description", new SetSpanErrorParameter( - s -> Tracing.setSpanError(s, "error", exception), "error", exception)))); + s -> tracing.setSpanError(s, "error", exception), "error", exception)))); } @ParameterizedTest From 7d1da59c327637002e551106fcea9c6b989f28f1 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 25 Aug 2023 09:48:34 +0200 Subject: [PATCH 08/33] - remove GlobalTracing.java for now (discussion pending) - inject Tracer into Tracing, making it easier to use --- .../contrib/tracer/GlobalTracing.java | 129 ------------------ .../opentelemetry/contrib/tracer/Tracing.java | 9 +- ...lobalTracingTest.java => TracingTest.java} | 56 ++++---- 3 files changed, 36 insertions(+), 158 deletions(-) delete mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java rename extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/{GlobalTracingTest.java => TracingTest.java} (83%) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java deleted file mode 100644 index ed0ede821..000000000 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/GlobalTracing.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.tracer; - -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.context.Context; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.function.BiConsumer; - -/** - * Tracing utility methods that rely on the {@link io.opentelemetry.api.GlobalOpenTelemetry} - * instance. - * - *

If the application is not running in javaagent, the first call to any of the methods in this - * class may trigger the initialization of the {@link io.opentelemetry.api.GlobalOpenTelemetry} * - * instance. - */ -public class GlobalTracing { - private GlobalTracing() {} - - /** - * Return the tracer to be used in a service - * - * @return the tracer to be used in a service - */ - public static Tracer serviceTracer() { - return GlobalOpenTelemetry.getTracer("service"); - } - - private static Tracing tracing() { - return new Tracing(GlobalOpenTelemetry.get()); - } - - public static void run(String spanName, Runnable runnable) { - tracing().run(serviceTracer(), spanName, runnable); - } - - /** - * Runs a block of code with a new span - ending the span at the end and recording any exception. - * - * @param spanName name of the new span - */ - public static T call(String spanName, Callable callable) { - return tracing().call(serviceTracer(), spanName, callable); - } - - /** - * Creates a new span builder with the given span name. - * - * @param spanName the span name - * @return the span builder - */ - public static SpanBuilder withSpan(String spanName) { - return serviceTracer().spanBuilder(spanName); - } - - /** - * Injects the current context into a string map, which can then be added to HTTP headers or the - * metadata of an event. - */ - public static Map getPropagationHeaders() { - return tracing().getPropagationHeaders(); - } - - /** - * Extract the context from a string map, which you get from HTTP headers of the metadata of an - * event you're processing. - */ - public static Context extractContext(Map transport) { - return tracing().extractContext(transport); - } - - /** - * Trace a block of code using a server span. - * - *

The span context will be extracted from the transport, which you usually get - * from HTTP headers of the metadata of an event you're processing. - */ - public static T traceServerSpan( - Map transport, SpanBuilder spanBuilder, Callable callable) { - return tracing().traceServerSpan(transport, spanBuilder, callable); - } - - /** - * Trace a block of code using a server span. - * - *

The span context will be extracted from the transport, which you usually get - * from HTTP headers of the metadata of an event you're processing. - */ - public static T traceServerSpan( - Map transport, - SpanBuilder spanBuilder, - Callable callable, - BiConsumer handleException) { - return tracing().traceServerSpan(transport, spanBuilder, callable, handleException); - } - - /** - * Trace a block of code using a consumer span. - * - *

The span context will be extracted from the transport, which you usually get - * from HTTP headers of the metadata of an event you're processing. - */ - public static T traceConsumerSpan( - Map transport, SpanBuilder spanBuilder, Callable callable) { - return tracing().traceConsumerSpan(transport, spanBuilder, callable); - } - - /** - * Trace a block of code using a consumer span. - * - *

The span context will be extracted from the transport, which you usually get - * from HTTP headers of the metadata of an event you're processing. - */ - public static T traceConsumerSpan( - Map transport, - SpanBuilder spanBuilder, - Callable callable, - BiConsumer handleException) { - return tracing().traceConsumerSpan(transport, spanBuilder, callable, handleException); - } -} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index 4bad68967..2cc85dc8d 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -46,11 +46,14 @@ public String get(@Nullable Map carrier, String key) { }; private final OpenTelemetry openTelemetry; - public Tracing(OpenTelemetry openTelemetry) { + private final Tracer tracer; + + public Tracing(OpenTelemetry openTelemetry, String tracerName) { this.openTelemetry = openTelemetry; + this.tracer = openTelemetry.getTracer(tracerName); } - public void run(Tracer tracer, String spanName, Runnable runnable) { + public void run(String spanName, Runnable runnable) { runAndEndSpan(tracer.spanBuilder(spanName).startSpan(), runnable); } @@ -68,7 +71,7 @@ public void runAndEndSpan(Span span, Runnable runnable) { * * @param spanName name of the new span */ - public T call(Tracer tracer, String spanName, Callable callable) { + public T call(String spanName, Callable callable) { return callAndEndSpan(tracer.spanBuilder(spanName).startSpan(), callable); } diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java similarity index 83% rename from extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java rename to extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index 9d05692cd..e6e8d3285 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/GlobalTracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -14,6 +14,7 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; @@ -32,29 +33,31 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -public class GlobalTracingTest { +public class TracingTest { @RegisterExtension static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); - private final Tracing tracing = new Tracing(otelTesting.getOpenTelemetry()); + private final Tracing tracing = new Tracing(otelTesting.getOpenTelemetry(), "test"); + + private final Tracer tracer = otelTesting.getOpenTelemetry().getTracer("test"); @Test void propagation() { - GlobalTracing.run( + tracing.run( "parent", () -> { - Map propagationHeaders = GlobalTracing.getPropagationHeaders(); + Map propagationHeaders = tracing.getPropagationHeaders(); assertThat(propagationHeaders).hasSize(1).containsKey("traceparent"); assertThat( - Span.fromContext(GlobalTracing.extractContext(propagationHeaders)) - .getSpanContext() - .getSpanId()) + Span.fromContext(tracing.extractContext(propagationHeaders)) + .getSpanContext() + .getSpanId()) .isEqualTo(Span.current().getSpanContext().getSpanId()); - GlobalTracing.traceServerSpan( - propagationHeaders, GlobalTracing.withSpan("child"), () -> null); + tracing.traceServerSpan( + propagationHeaders, tracer.spanBuilder("child"), () -> null); }); otelTesting @@ -69,7 +72,7 @@ void propagation() { @Test void callWithBaggage() { String value = - GlobalTracing.call( + tracing.call( "parent", () -> tracing.callWithBaggage( @@ -80,12 +83,12 @@ void callWithBaggage() { } private static class ExtractAndRunParameter { - private final Consumer> extractAndRun; + private final BiConsumer> extractAndRun; private final SpanKind wantKind; private final StatusData wantStatus; private ExtractAndRunParameter( - Consumer> extractAndRun, SpanKind wantKind, StatusData wantStatus) { + BiConsumer> extractAndRun, SpanKind wantKind, StatusData wantStatus) { this.extractAndRun = extractAndRun; this.wantKind = wantKind; this.wantStatus = wantStatus; @@ -103,19 +106,19 @@ private static Stream extractAndRun() { named( "server", new ExtractAndRunParameter( - c -> - GlobalTracing.traceServerSpan( - Collections.emptyMap(), GlobalTracing.withSpan("span"), c), + (t, c) -> + t.tracing.traceServerSpan( + Collections.emptyMap(), t.tracer.spanBuilder("span"), c), io.opentelemetry.api.trace.SpanKind.SERVER, io.opentelemetry.sdk.trace.data.StatusData.error()))), Arguments.of( named( "server - ignore exception", new ExtractAndRunParameter( - c -> - GlobalTracing.traceServerSpan( + (t, c) -> + t.tracing.traceServerSpan( Collections.emptyMap(), - GlobalTracing.withSpan("span"), + t.tracer.spanBuilder("span"), c, ignoreException), io.opentelemetry.api.trace.SpanKind.SERVER, @@ -124,19 +127,19 @@ private static Stream extractAndRun() { named( "consumer", new ExtractAndRunParameter( - c -> - GlobalTracing.traceConsumerSpan( - Collections.emptyMap(), GlobalTracing.withSpan("span"), c), + (t, c) -> + t.tracing.traceConsumerSpan( + Collections.emptyMap(), t.tracer.spanBuilder("span"), c), io.opentelemetry.api.trace.SpanKind.CONSUMER, io.opentelemetry.sdk.trace.data.StatusData.error()))), Arguments.of( named( "consumer - ignore exception", new ExtractAndRunParameter( - c -> - GlobalTracing.traceConsumerSpan( + (t, c) -> + t.tracing.traceConsumerSpan( Collections.emptyMap(), - GlobalTracing.withSpan("span"), + t.tracer.spanBuilder("span"), c, ignoreException), io.opentelemetry.api.trace.SpanKind.CONSUMER, @@ -150,6 +153,7 @@ void extractAndRun(ExtractAndRunParameter parameter) { .isThrownBy( () -> parameter.extractAndRun.accept( + this, () -> { throw new RuntimeException("ex"); })); @@ -178,7 +182,7 @@ private SetSpanErrorParameter( @Keep private static Stream setSpanError() { - Tracing tracing = new Tracing(otelTesting.getOpenTelemetry()); + Tracing tracing = new Tracing(otelTesting.getOpenTelemetry(), "test"); RuntimeException exception = new RuntimeException("ex"); return Stream.of( Arguments.of( @@ -200,7 +204,7 @@ private static Stream setSpanError() { @ParameterizedTest @MethodSource void setSpanError(SetSpanErrorParameter parameter) { - GlobalTracing.run("parent", () -> parameter.setError.accept(Span.current())); + tracing.run("parent", () -> parameter.setError.accept(Span.current())); otelTesting .assertTraces() From 7df83e794b9c6e4b0b06f59e7918a7eed59c12bc Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 25 Aug 2023 10:44:34 +0200 Subject: [PATCH 09/33] add before/after comparison for extended tracer --- extended-tracer/README.md | 136 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/extended-tracer/README.md b/extended-tracer/README.md index 37c2b2968..cb073d6ff 100644 --- a/extended-tracer/README.md +++ b/extended-tracer/README.md @@ -1,6 +1,142 @@ # extended-tracer Utility methods to make it easier to use the OpenTelemetry tracer. + +## Usage Examples + +Here are some examples how the utility methods can help reduce boilerplate code. + +### Tracing a function + +Before: + +```java +Span span = tracer.spanBuilder("reset_checkout").startSpan(); +String transactionId; +try (Scope scope = span.makeCurrent()) { + transactionId = resetCheckout(cartId); +} catch (Exception e) { + span.setStatus(StatusCode.ERROR); + span.recordException(e); + throw e; +} finally { + span.end(); +} +``` + +After: +```java +Tracing tracing = new Tracing(openTelemetry, "service"); +String transactionId = tracing.call("reset_checkout", () -> resetCheckout(cartId)); +``` + +Note: Use `run` instead of `call` if the function returns `void`. + +### Trace context propagation + +Before: + +```java +Map propagationHeaders = new HashMap<>(); +openTelemetry + .getPropagators() + .getTextMapPropagator() + .inject( + Context.current(), + propagationHeaders, + (map, key, value) -> { + if (map != null) { + map.put(key, value); + } + }); + +// add propagationHeaders to request headers and call checkout service +``` + +```java +// in checkout service: get request headers into a Map requestHeaders +Map requestHeaders = new HashMap<>(); +String cartId = "cartId"; + +SpanBuilder spanBuilder = tracer.spanBuilder("checkout_cart"); +String transactionId; + +TextMapGetter> TEXT_MAP_GETTER = + new TextMapGetter>() { + @Override + public Set keys(Map carrier) { + return carrier.keySet(); + } + + @Override + @Nullable + public String get(@Nullable Map carrier, String key) { + //noinspection ConstantConditions + return carrier == null ? null : carrier.get(key); + } + }; + +Map normalizedTransport = + requestHeaders.entrySet().stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue)); +Context newContext = openTelemetry + .getPropagators() + .getTextMapPropagator() + .extract(Context.current(), normalizedTransport, TEXT_MAP_GETTER); +try (Scope ignore = newContext.makeCurrent()) { + Span span = spanBuilder.setSpanKind(SERVER).startSpan(); + try (Scope scope = span.makeCurrent()) { + transactionId = processCheckout(cartId); + } catch (Exception e) { + span.setStatus(StatusCode.ERROR); + span.recordException(e); + throw e; + } finally { + span.end(); + } +} +``` + +After: + +```java +Tracing tracing = new Tracing(openTelemetry, "service"); +Map propagationHeaders = tracing.getPropagationHeaders(); +// add propagationHeaders to request headers and call checkout service +``` + +```java +// in checkout service: get request headers into a Map requestHeaders +Map requestHeaders = new HashMap<>(); +String cartId = "cartId"; + +Tracing tracing = new Tracing(openTelemetry, "service"); +String transactionId = tracing.traceServerSpan(requestHeaders, + tracer.spanBuilder("checkout_cart"), () -> processCheckout(cartId)); +``` + +### Setting baggage entries + +Before: + +```java +BaggageBuilder builder = Baggage.current().toBuilder(); +builder.put("key", "value"); +Context context = builder.build().storeInContext(Context.current()); +try (Scope ignore = context.makeCurrent()) { + String value = Baggage.current().getEntryValue("key"); +} +``` + +After: +```java +Tracing tracing = new Tracing(openTelemetry, "service"); +String value = tracing.callWithBaggage( + Collections.singletonMap("key", "value"), + () -> Baggage.current().getEntryValue("key")) +``` --- From 176f116cc6f094d77a3814f071a285a3dd494531 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 25 Aug 2023 10:46:04 +0200 Subject: [PATCH 10/33] - remove GlobalTracing.java for now (discussion pending) - inject Tracer into Tracing, making it easier to use --- .../opentelemetry/contrib/tracer/TracingTest.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index e6e8d3285..e2555bdc1 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -51,13 +51,12 @@ void propagation() { assertThat(propagationHeaders).hasSize(1).containsKey("traceparent"); assertThat( - Span.fromContext(tracing.extractContext(propagationHeaders)) - .getSpanContext() - .getSpanId()) + Span.fromContext(tracing.extractContext(propagationHeaders)) + .getSpanContext() + .getSpanId()) .isEqualTo(Span.current().getSpanContext().getSpanId()); - tracing.traceServerSpan( - propagationHeaders, tracer.spanBuilder("child"), () -> null); + tracing.traceServerSpan(propagationHeaders, tracer.spanBuilder("child"), () -> null); }); otelTesting @@ -88,7 +87,9 @@ private static class ExtractAndRunParameter { private final StatusData wantStatus; private ExtractAndRunParameter( - BiConsumer> extractAndRun, SpanKind wantKind, StatusData wantStatus) { + BiConsumer> extractAndRun, + SpanKind wantKind, + StatusData wantStatus) { this.extractAndRun = extractAndRun; this.wantKind = wantKind; this.wantStatus = wantStatus; From 96194284184f371f9ee3344d675dcab47b33d63b Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 25 Aug 2023 11:26:18 +0200 Subject: [PATCH 11/33] add before/after comparison for extended tracer --- extended-tracer/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/extended-tracer/README.md b/extended-tracer/README.md index cb073d6ff..727f2c669 100644 --- a/extended-tracer/README.md +++ b/extended-tracer/README.md @@ -1,7 +1,7 @@ # extended-tracer Utility methods to make it easier to use the OpenTelemetry tracer. - + ## Usage Examples Here are some examples how the utility methods can help reduce boilerplate code. @@ -31,7 +31,7 @@ String transactionId = tracing.call("reset_checkout", () -> resetCheckout(cartId ``` Note: Use `run` instead of `call` if the function returns `void`. - + ### Trace context propagation Before: @@ -51,8 +51,8 @@ openTelemetry }); // add propagationHeaders to request headers and call checkout service -``` - +``` + ```java // in checkout service: get request headers into a Map requestHeaders Map requestHeaders = new HashMap<>(); @@ -106,17 +106,17 @@ Tracing tracing = new Tracing(openTelemetry, "service"); Map propagationHeaders = tracing.getPropagationHeaders(); // add propagationHeaders to request headers and call checkout service ``` - + ```java // in checkout service: get request headers into a Map requestHeaders Map requestHeaders = new HashMap<>(); String cartId = "cartId"; - + Tracing tracing = new Tracing(openTelemetry, "service"); -String transactionId = tracing.traceServerSpan(requestHeaders, +String transactionId = tracing.traceServerSpan(requestHeaders, tracer.spanBuilder("checkout_cart"), () -> processCheckout(cartId)); ``` - + ### Setting baggage entries Before: From fa0a83a4c56f582560a9af12ac9b8c0ca2023f85 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 25 Aug 2023 11:36:36 +0200 Subject: [PATCH 12/33] add before/after comparison for extended tracer --- extended-tracer/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extended-tracer/README.md b/extended-tracer/README.md index 727f2c669..0d5e4134f 100644 --- a/extended-tracer/README.md +++ b/extended-tracer/README.md @@ -25,6 +25,7 @@ try (Scope scope = span.makeCurrent()) { ``` After: + ```java Tracing tracing = new Tracing(openTelemetry, "service"); String transactionId = tracing.call("reset_checkout", () -> resetCheckout(cartId)); @@ -131,6 +132,7 @@ try (Scope ignore = context.makeCurrent()) { ``` After: + ```java Tracing tracing = new Tracing(openTelemetry, "service"); String value = tracing.callWithBaggage( From 8e348cc92bca0e6146ce3cb64fadb6d4a701312d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 28 Aug 2023 10:48:50 +0200 Subject: [PATCH 13/33] - catch & re-throw Throwable over Exception everywhere - clarify error handling strategy --- extended-tracer/README.md | 31 +++++++++++++++---- .../opentelemetry/contrib/tracer/Tracing.java | 10 +++--- .../contrib/tracer/TracingTest.java | 2 +- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/extended-tracer/README.md b/extended-tracer/README.md index 0d5e4134f..351d62e2c 100644 --- a/extended-tracer/README.md +++ b/extended-tracer/README.md @@ -15,10 +15,10 @@ Span span = tracer.spanBuilder("reset_checkout").startSpan(); String transactionId; try (Scope scope = span.makeCurrent()) { transactionId = resetCheckout(cartId); -} catch (Exception e) { +} catch (Throwable e) { span.setStatus(StatusCode.ERROR); span.recordException(e); - throw e; + throw e; // or throw new RuntimeException(e) - depending on your error handling strategy } finally { span.end(); } @@ -31,7 +31,11 @@ Tracing tracing = new Tracing(openTelemetry, "service"); String transactionId = tracing.call("reset_checkout", () -> resetCheckout(cartId)); ``` -Note: Use `run` instead of `call` if the function returns `void`. +Note: + +- Use `run` instead of `call` if the function returns `void`. +- Exceptions are re-thrown without modification - see [Exception handling](#exception-handling) + for more details. ### Trace context propagation @@ -90,10 +94,10 @@ try (Scope ignore = newContext.makeCurrent()) { Span span = spanBuilder.setSpanKind(SERVER).startSpan(); try (Scope scope = span.makeCurrent()) { transactionId = processCheckout(cartId); - } catch (Exception e) { + } catch (Throwable e) { span.setStatus(StatusCode.ERROR); span.recordException(e); - throw e; + throw e; // or throw new RuntimeException(e) - depending on your error handling strategy } finally { span.end(); } @@ -118,6 +122,13 @@ String transactionId = tracing.traceServerSpan(requestHeaders, tracer.spanBuilder("checkout_cart"), () -> processCheckout(cartId)); ``` +Note: + +- You can use `traceConsumerSpan` if you want to trace a consumer (e.g. from a message queue) + instead of a server. +- Exceptions are re-thrown without modification - see [Exception handling](#exception-handling) + for more details. + ### Setting baggage entries Before: @@ -140,7 +151,15 @@ String value = tracing.callWithBaggage( () -> Baggage.current().getEntryValue("key")) ``` ---- +## Exception handling + +`Tracing` re-throws exceptions without modification. This means you can catch exceptions around +`Tracing` calls and handle them as you would without `Tracing`. + +Note that the `Tracing` methods do not declare any checked exceptions +(the idea is taken from [@SneakyThrows](https://projectlombok.org/features/SneakyThrows)). +Declaring a checked exception would force callers to handle it, which would create a lot of +boilerplate code. Instead, `Tracing` re-throws checked exceptions as unchecked exceptions. ## Component owners diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index 2cc85dc8d..ccacaebf1 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -81,11 +81,11 @@ public T callAndEndSpan(Span span, Callable callable) { @SuppressWarnings("NullAway") public T callAndEndSpan( - Span span, Callable callable, BiConsumer handleException) { + Span span, Callable callable, BiConsumer handleException) { //noinspection unused try (Scope scope = span.makeCurrent()) { return callable.call(); - } catch (Exception e) { + } catch (Throwable e) { handleException.accept(span, e); sneakyThrow(e); return null; @@ -207,7 +207,7 @@ public T traceServerSpan( Map transport, SpanBuilder spanBuilder, Callable callable, - BiConsumer handleException) { + BiConsumer handleException) { return extractAndRun(SERVER, transport, spanBuilder, callable, handleException); } @@ -232,7 +232,7 @@ public T traceConsumerSpan( Map transport, SpanBuilder spanBuilder, Callable callable, - BiConsumer handleException) { + BiConsumer handleException) { return extractAndRun(CONSUMER, transport, spanBuilder, callable, handleException); } @@ -241,7 +241,7 @@ private T extractAndRun( Map transport, SpanBuilder spanBuilder, Callable callable, - BiConsumer handleException) { + BiConsumer handleException) { try (Scope ignore = extractContext(transport).makeCurrent()) { return callAndEndSpan( spanBuilder.setSpanKind(spanKind).startSpan(), callable, handleException); diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index e2555bdc1..40267dd7b 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -98,7 +98,7 @@ private ExtractAndRunParameter( @Keep private static Stream extractAndRun() { - BiConsumer ignoreException = + BiConsumer ignoreException = (span, throwable) -> { // ignore }; From 5cbb7f837af1f3d5ccdaa20fd2bfc906874cc469 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 Sep 2023 09:57:12 +0200 Subject: [PATCH 14/33] add javadoc --- .../opentelemetry/contrib/tracer/Tracing.java | 147 +++++++++++++++++- .../contrib/tracer/TracingTest.java | 33 ++-- 2 files changed, 149 insertions(+), 31 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index ccacaebf1..b294bd699 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -28,6 +28,13 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; +/** + * Utility class to simplify tracing. + * + *

The README + * explains the use cases in more detail. + */ public final class Tracing { private static final TextMapGetter> TEXT_MAP_GETTER = @@ -48,15 +55,60 @@ public String get(@Nullable Map carrier, String key) { private final Tracer tracer; + /** + * Creates a new instance of {@link Tracing}. + * + * @param openTelemetry the {@link OpenTelemetry} instance + * @param tracerName the name of the tracer to use + */ public Tracing(OpenTelemetry openTelemetry, String tracerName) { + this(openTelemetry, openTelemetry.getTracer(tracerName)); + } + + /** + * Creates a new instance of {@link Tracing}. + * + * @param openTelemetry the {@link OpenTelemetry} instance + * @param tracer the {@link Tracer} to use + */ + public Tracing(OpenTelemetry openTelemetry, Tracer tracer) { this.openTelemetry = openTelemetry; - this.tracer = openTelemetry.getTracer(tracerName); + this.tracer = tracer; } + /** + * Creates a new {@link SpanBuilder} with the given span name. + * + * @param spanName the name of the span + * @return the {@link SpanBuilder} + */ + public SpanBuilder spanBuilder(String spanName) { + return tracer.spanBuilder(spanName); + } + + /** + * Runs the given {@link Runnable} in a new span with the given name. + * + *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the + * exception will be recorded. + * + * @param spanName the name of the span + * @param runnable the {@link Runnable} to run + */ public void run(String spanName, Runnable runnable) { runAndEndSpan(tracer.spanBuilder(spanName).startSpan(), runnable); } + /** + * Runs the given {@link Runnable} inside of the given span. The span will be ended at the end of + * the {@link Runnable}. + * + *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the + * exception will be recorded. + * + * @param span the span to use + * @param runnable the {@link Runnable} to run + */ public void runAndEndSpan(Span span, Runnable runnable) { callAndEndSpan( span, @@ -67,18 +119,50 @@ public void runAndEndSpan(Span span, Runnable runnable) { } /** - * Runs a block of code with a new span - ending the span at the end and recording any exception. + * Runs the given {@link Callable} inside a new span with the given name. + * + *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the + * exception will be recorded. * - * @param spanName name of the new span + * @param spanName the name of the span + * @param callable the {@link Callable} to call + * @param the type of the result + * @return the result of the {@link Callable} */ public T call(String spanName, Callable callable) { return callAndEndSpan(tracer.spanBuilder(spanName).startSpan(), callable); } + /** + * Runs the given {@link Callable} inside of the given span. The span will be ended at the end of + * the {@link Callable}. + * + *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the + * exception will be recorded. + * + * @param span the span to use + * @param callable the {@link Callable} to call + * @param the type of the result + * @return the result of the {@link Callable} + */ public T callAndEndSpan(Span span, Callable callable) { return callAndEndSpan(span, callable, this::setSpanError); } + /** + * Runs the given {@link Callable} inside of the given span. The span will be ended at the end of + * the {@link Callable}. + * + *

If an exception is thrown by the {@link Runnable}, the handleException consumer will be + * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not + * marking the span as error. + * + * @param span the span to use + * @param callable the {@link Callable} to call + * @param handleException the consumer to call when an exception is thrown + * @param the type of the result + * @return the result of the {@link Callable} + */ @SuppressWarnings("NullAway") public T callAndEndSpan( Span span, Callable callable, BiConsumer handleException) { @@ -172,7 +256,14 @@ public Context extractContext(Map transport) { .extract(current, normalizedTransport, TEXT_MAP_GETTER); } - /** Sets baggage items which are active in given block. */ + /** + * Set baggage items inside the given {@link Callable}. + * + * @param baggage the baggage items to set + * @param callable the {@link Callable} to call + * @param the type of the result + * @return the result of the {@link Callable} + */ @SuppressWarnings("NullAway") public T callWithBaggage(Map baggage, Callable callable) { BaggageBuilder builder = Baggage.current().toBuilder(); @@ -187,10 +278,19 @@ public T callWithBaggage(Map baggage, Callable callable) } /** - * Trace a block of code using a server span. + * Run the given {@link Runnable} inside a server span. * *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. + * + *

If an exception is thrown by the {@link Callable}, the span will be marked as error, and the + * exception will be recorded. + * + * @param transport the transport where to extract the span context from + * @param spanBuilder the {@link SpanBuilder} to use + * @param callable the {@link Callable} to call + * @param the type of the result + * @return the result of the {@link Callable} */ public T traceServerSpan( Map transport, SpanBuilder spanBuilder, Callable callable) { @@ -198,10 +298,21 @@ public T traceServerSpan( } /** - * Trace a block of code using a server span. + * Run the given {@link Runnable} inside a server span. * *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. + * + *

If an exception is thrown by the {@link Runnable}, the handleException consumer will be + * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not + * marking the span as error. + * + * @param transport the transport where to extract the span context from + * @param spanBuilder the {@link SpanBuilder} to use + * @param callable the {@link Callable} to call + * @param handleException the consumer to call when an exception is thrown + * @param the type of the result + * @return the result of the {@link Callable} */ public T traceServerSpan( Map transport, @@ -212,10 +323,19 @@ public T traceServerSpan( } /** - * Trace a block of code using a consumer span. + * Run the given {@link Runnable} inside a server span. * *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. + * + *

If an exception is thrown by the {@link Callable}, the span will be marked as error, and the + * exception will be recorded. + * + * @param transport the transport where to extract the span context from + * @param spanBuilder the {@link SpanBuilder} to use + * @param callable the {@link Callable} to call + * @param the type of the result + * @return the result of the {@link Callable} */ public T traceConsumerSpan( Map transport, SpanBuilder spanBuilder, Callable callable) { @@ -223,10 +343,21 @@ public T traceConsumerSpan( } /** - * Trace a block of code using a consumer span. + * Run the given {@link Runnable} inside a consumer span. * *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. + * + *

If an exception is thrown by the {@link Runnable}, the handleException consumer will be + * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not + * marking the span as error. + * + * @param transport the transport where to extract the span context from + * @param spanBuilder the {@link SpanBuilder} to use + * @param callable the {@link Callable} to call + * @param handleException the consumer to call when an exception is thrown + * @param the type of the result + * @return the result of the {@link Callable} */ public T traceConsumerSpan( Map transport, diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index 40267dd7b..6b663eef4 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -14,7 +14,6 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; @@ -40,8 +39,6 @@ public class TracingTest { private final Tracing tracing = new Tracing(otelTesting.getOpenTelemetry(), "test"); - private final Tracer tracer = otelTesting.getOpenTelemetry().getTracer("test"); - @Test void propagation() { tracing.run( @@ -56,7 +53,7 @@ void propagation() { .getSpanId()) .isEqualTo(Span.current().getSpanContext().getSpanId()); - tracing.traceServerSpan(propagationHeaders, tracer.spanBuilder("child"), () -> null); + tracing.traceServerSpan(propagationHeaders, tracing.spanBuilder("child"), () -> null); }); otelTesting @@ -82,12 +79,12 @@ void callWithBaggage() { } private static class ExtractAndRunParameter { - private final BiConsumer> extractAndRun; + private final BiConsumer> extractAndRun; private final SpanKind wantKind; private final StatusData wantStatus; private ExtractAndRunParameter( - BiConsumer> extractAndRun, + BiConsumer> extractAndRun, SpanKind wantKind, StatusData wantStatus) { this.extractAndRun = extractAndRun; @@ -107,9 +104,7 @@ private static Stream extractAndRun() { named( "server", new ExtractAndRunParameter( - (t, c) -> - t.tracing.traceServerSpan( - Collections.emptyMap(), t.tracer.spanBuilder("span"), c), + (t, c) -> t.traceServerSpan(Collections.emptyMap(), t.spanBuilder("span"), c), io.opentelemetry.api.trace.SpanKind.SERVER, io.opentelemetry.sdk.trace.data.StatusData.error()))), Arguments.of( @@ -117,20 +112,15 @@ private static Stream extractAndRun() { "server - ignore exception", new ExtractAndRunParameter( (t, c) -> - t.tracing.traceServerSpan( - Collections.emptyMap(), - t.tracer.spanBuilder("span"), - c, - ignoreException), + t.traceServerSpan( + Collections.emptyMap(), t.spanBuilder("span"), c, ignoreException), io.opentelemetry.api.trace.SpanKind.SERVER, io.opentelemetry.sdk.trace.data.StatusData.unset()))), Arguments.of( named( "consumer", new ExtractAndRunParameter( - (t, c) -> - t.tracing.traceConsumerSpan( - Collections.emptyMap(), t.tracer.spanBuilder("span"), c), + (t, c) -> t.traceConsumerSpan(Collections.emptyMap(), t.spanBuilder("span"), c), io.opentelemetry.api.trace.SpanKind.CONSUMER, io.opentelemetry.sdk.trace.data.StatusData.error()))), Arguments.of( @@ -138,11 +128,8 @@ private static Stream extractAndRun() { "consumer - ignore exception", new ExtractAndRunParameter( (t, c) -> - t.tracing.traceConsumerSpan( - Collections.emptyMap(), - t.tracer.spanBuilder("span"), - c, - ignoreException), + t.traceConsumerSpan( + Collections.emptyMap(), t.spanBuilder("span"), c, ignoreException), io.opentelemetry.api.trace.SpanKind.CONSUMER, io.opentelemetry.sdk.trace.data.StatusData.unset())))); } @@ -154,7 +141,7 @@ void extractAndRun(ExtractAndRunParameter parameter) { .isThrownBy( () -> parameter.extractAndRun.accept( - this, + tracing, () -> { throw new RuntimeException("ex"); })); From db2263d24d1b5e75e7ad21c733ae5e951107d817 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 6 Sep 2023 12:43:19 +0200 Subject: [PATCH 15/33] take span builder instead of span to reinforce that the span is started and ended by run/call --- .../opentelemetry/contrib/tracer/Tracing.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index b294bd699..4df4f46d6 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -96,22 +96,22 @@ public SpanBuilder spanBuilder(String spanName) { * @param runnable the {@link Runnable} to run */ public void run(String spanName, Runnable runnable) { - runAndEndSpan(tracer.spanBuilder(spanName).startSpan(), runnable); + run(tracer.spanBuilder(spanName), runnable); } /** - * Runs the given {@link Runnable} inside of the given span. The span will be ended at the end of - * the {@link Runnable}. + * Runs the given {@link Runnable} inside of the span created by the given {@link SpanBuilder}. + * The span will be ended at the end of the {@link Runnable}. * *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the * exception will be recorded. * - * @param span the span to use + * @param spanBuilder the {@link SpanBuilder} to use * @param runnable the {@link Runnable} to run */ - public void runAndEndSpan(Span span, Runnable runnable) { - callAndEndSpan( - span, + public void run(SpanBuilder spanBuilder, Runnable runnable) { + call( + spanBuilder, () -> { runnable.run(); return null; @@ -130,44 +130,45 @@ public void runAndEndSpan(Span span, Runnable runnable) { * @return the result of the {@link Callable} */ public T call(String spanName, Callable callable) { - return callAndEndSpan(tracer.spanBuilder(spanName).startSpan(), callable); + return call(tracer.spanBuilder(spanName), callable); } /** - * Runs the given {@link Callable} inside of the given span. The span will be ended at the end of - * the {@link Callable}. + * Runs the given {@link Callable} inside of the span created by the given {@link SpanBuilder}. + * The span will be ended at the end of the {@link Callable}. * *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the * exception will be recorded. * - * @param span the span to use + * @param spanBuilder the {@link SpanBuilder} to use * @param callable the {@link Callable} to call * @param the type of the result * @return the result of the {@link Callable} */ - public T callAndEndSpan(Span span, Callable callable) { - return callAndEndSpan(span, callable, this::setSpanError); + public T call(SpanBuilder spanBuilder, Callable callable) { + return call(spanBuilder, callable, this::setSpanError); } /** - * Runs the given {@link Callable} inside of the given span. The span will be ended at the end of - * the {@link Callable}. + * Runs the given {@link Callable} inside of the span created by the given {@link SpanBuilder}. + * The span will be ended at the end of the {@link Callable}. * *

If an exception is thrown by the {@link Runnable}, the handleException consumer will be * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not * marking the span as error. * - * @param span the span to use + * @param spanBuilder the {@link SpanBuilder} to use * @param callable the {@link Callable} to call * @param handleException the consumer to call when an exception is thrown * @param the type of the result * @return the result of the {@link Callable} */ @SuppressWarnings("NullAway") - public T callAndEndSpan( - Span span, Callable callable, BiConsumer handleException) { + public T call( + SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { + Span span = spanBuilder.startSpan(); //noinspection unused - try (Scope scope = span.makeCurrent()) { + try (Scope unused = span.makeCurrent()) { return callable.call(); } catch (Throwable e) { handleException.accept(span, e); @@ -374,8 +375,7 @@ private T extractAndRun( Callable callable, BiConsumer handleException) { try (Scope ignore = extractContext(transport).makeCurrent()) { - return callAndEndSpan( - spanBuilder.setSpanKind(spanKind).startSpan(), callable, handleException); + return call(spanBuilder.setSpanKind(spanKind), callable, handleException); } } From 6b35e784290b594de9133b0f3704c1b796783672 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 18 Sep 2023 11:25:17 +0200 Subject: [PATCH 16/33] use throwing supplier which avoids using sneaky throws --- extended-tracer/build.gradle.kts | 2 +- .../contrib/tracer/ThrowingSupplier.java | 18 ++ .../opentelemetry/contrib/tracer/Tracing.java | 168 ++++++++++-------- .../contrib/tracer/TracingTest.java | 11 +- 4 files changed, 117 insertions(+), 82 deletions(-) create mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java diff --git a/extended-tracer/build.gradle.kts b/extended-tracer/build.gradle.kts index 8b91f75c4..3f904c8fc 100644 --- a/extended-tracer/build.gradle.kts +++ b/extended-tracer/build.gradle.kts @@ -13,5 +13,5 @@ otelJava { dependencies { api("io.opentelemetry:opentelemetry-api") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") - testImplementation("io.opentelemetry:opentelemetry-semconv") + testImplementation("io.opentelemetry.semconv:opentelemetry-semconv") } diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java new file mode 100644 index 000000000..bd25c7a61 --- /dev/null +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.tracer; + +import java.util.function.Supplier; + +/** + * A utility interface representing a {@link Supplier} that may throw. + * + * @param Thrown exception type. + */ +@FunctionalInterface +public interface ThrowingSupplier { + T get() throws E; +} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index 4df4f46d6..b5b3fea9a 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -23,7 +23,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.Callable; import java.util.function.BiConsumer; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -109,6 +108,7 @@ public void run(String spanName, Runnable runnable) { * @param spanBuilder the {@link SpanBuilder} to use * @param runnable the {@link Runnable} to run */ + @SuppressWarnings("NullAway") public void run(SpanBuilder spanBuilder, Runnable runnable) { call( spanBuilder, @@ -119,61 +119,68 @@ public void run(SpanBuilder spanBuilder, Runnable runnable) { } /** - * Runs the given {@link Callable} inside a new span with the given name. + * Runs the given {@link ThrowingSupplier} inside a new span with the given name. * - *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the - * exception will be recorded. + *

If an exception is thrown by the {@link ThrowingSupplier}, the span will be marked as error, + * and the exception will be recorded. * * @param spanName the name of the span - * @param callable the {@link Callable} to call + * @param throwingSupplier the {@link ThrowingSupplier} to call * @param the type of the result - * @return the result of the {@link Callable} + * @param the type of the exception + * @return the result of the {@link ThrowingSupplier} */ - public T call(String spanName, Callable callable) { - return call(tracer.spanBuilder(spanName), callable); + public T call(String spanName, ThrowingSupplier throwingSupplier) + throws E { + return call(tracer.spanBuilder(spanName), throwingSupplier); } /** - * Runs the given {@link Callable} inside of the span created by the given {@link SpanBuilder}. - * The span will be ended at the end of the {@link Callable}. + * Runs the given {@link ThrowingSupplier} inside of the span created by the given {@link + * SpanBuilder}. The span will be ended at the end of the {@link ThrowingSupplier}. * - *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the - * exception will be recorded. + *

If an exception is thrown by the {@link ThrowingSupplier}, the span will be marked as error, + * and the exception will be recorded. * * @param spanBuilder the {@link SpanBuilder} to use - * @param callable the {@link Callable} to call + * @param throwingSupplier the {@link ThrowingSupplier} to call * @param the type of the result - * @return the result of the {@link Callable} + * @param the type of the exception + * @return the result of the {@link ThrowingSupplier} */ - public T call(SpanBuilder spanBuilder, Callable callable) { - return call(spanBuilder, callable, this::setSpanError); + public T call( + SpanBuilder spanBuilder, ThrowingSupplier throwingSupplier) throws E { + return call(spanBuilder, throwingSupplier, this::setSpanError); } /** - * Runs the given {@link Callable} inside of the span created by the given {@link SpanBuilder}. - * The span will be ended at the end of the {@link Callable}. + * Runs the given {@link ThrowingSupplier} inside of the span created by the given {@link + * SpanBuilder}. The span will be ended at the end of the {@link ThrowingSupplier}. * - *

If an exception is thrown by the {@link Runnable}, the handleException consumer will be - * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not - * marking the span as error. + *

If an exception is thrown by the {@link ThrowingSupplier}, the handleException consumer will + * be called, giving you the opportunity to handle the exception and span in a custom way, e.g. + * not marking the span as error. * * @param spanBuilder the {@link SpanBuilder} to use - * @param callable the {@link Callable} to call + * @param throwingSupplier the {@link ThrowingSupplier} to call * @param handleException the consumer to call when an exception is thrown * @param the type of the result - * @return the result of the {@link Callable} + * @param the type of the exception + * @return the result of the {@link ThrowingSupplier} */ @SuppressWarnings("NullAway") - public T call( - SpanBuilder spanBuilder, Callable callable, BiConsumer handleException) { + public T call( + SpanBuilder spanBuilder, + ThrowingSupplier throwingSupplier, + BiConsumer handleException) + throws E { Span span = spanBuilder.startSpan(); //noinspection unused try (Scope unused = span.makeCurrent()) { - return callable.call(); + return throwingSupplier.get(); } catch (Throwable e) { handleException.accept(span, e); - sneakyThrow(e); - return null; + throw e; } finally { span.end(); } @@ -258,23 +265,22 @@ public Context extractContext(Map transport) { } /** - * Set baggage items inside the given {@link Callable}. + * Set baggage items inside the given {@link ThrowingSupplier}. * * @param baggage the baggage items to set - * @param callable the {@link Callable} to call + * @param throwingSupplier the {@link ThrowingSupplier} to call * @param the type of the result - * @return the result of the {@link Callable} + * @param the type of the exception + * @return the result of the {@link ThrowingSupplier} */ @SuppressWarnings("NullAway") - public T callWithBaggage(Map baggage, Callable callable) { + public T callWithBaggage( + Map baggage, ThrowingSupplier throwingSupplier) throws E { BaggageBuilder builder = Baggage.current().toBuilder(); baggage.forEach(builder::put); Context context = builder.build().storeInContext(Context.current()); try (Scope ignore = context.makeCurrent()) { - return callable.call(); - } catch (Throwable e) { - sneakyThrow(e); - return null; + return throwingSupplier.get(); } } @@ -284,18 +290,22 @@ public T callWithBaggage(Map baggage, Callable callable) *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. * - *

If an exception is thrown by the {@link Callable}, the span will be marked as error, and the - * exception will be recorded. + *

If an exception is thrown by the {@link ThrowingSupplier}, the span will be marked as error, + * and the exception will be recorded. * * @param transport the transport where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use - * @param callable the {@link Callable} to call + * @param throwingSupplier the {@link ThrowingSupplier} to call * @param the type of the result - * @return the result of the {@link Callable} + * @param the type of the exception + * @return the result of the {@link ThrowingSupplier} */ - public T traceServerSpan( - Map transport, SpanBuilder spanBuilder, Callable callable) { - return extractAndRun(SERVER, transport, spanBuilder, callable, this::setSpanError); + public T traceServerSpan( + Map transport, + SpanBuilder spanBuilder, + ThrowingSupplier throwingSupplier) + throws E { + return extractAndRun(SERVER, transport, spanBuilder, throwingSupplier, this::setSpanError); } /** @@ -304,23 +314,25 @@ public T traceServerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. * - *

If an exception is thrown by the {@link Runnable}, the handleException consumer will be - * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not - * marking the span as error. + *

If an exception is thrown by the {@link ThrowingSupplier}, the handleException consumer will + * be called, giving you the opportunity to handle the exception and span in a custom way, e.g. + * not marking the span as error. * * @param transport the transport where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use - * @param callable the {@link Callable} to call + * @param throwingSupplier the {@link ThrowingSupplier} to call * @param handleException the consumer to call when an exception is thrown * @param the type of the result - * @return the result of the {@link Callable} + * @param the type of the exception + * @return the result of the {@link ThrowingSupplier} */ - public T traceServerSpan( + public T traceServerSpan( Map transport, SpanBuilder spanBuilder, - Callable callable, - BiConsumer handleException) { - return extractAndRun(SERVER, transport, spanBuilder, callable, handleException); + ThrowingSupplier throwingSupplier, + BiConsumer handleException) + throws E { + return extractAndRun(SERVER, transport, spanBuilder, throwingSupplier, handleException); } /** @@ -329,18 +341,22 @@ public T traceServerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. * - *

If an exception is thrown by the {@link Callable}, the span will be marked as error, and the - * exception will be recorded. + *

If an exception is thrown by the {@link ThrowingSupplier}, the span will be marked as error, + * and the exception will be recorded. * * @param transport the transport where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use - * @param callable the {@link Callable} to call + * @param throwingSupplier the {@link ThrowingSupplier} to call * @param the type of the result - * @return the result of the {@link Callable} + * @param the type of the exception + * @return the result of the {@link ThrowingSupplier} */ - public T traceConsumerSpan( - Map transport, SpanBuilder spanBuilder, Callable callable) { - return extractAndRun(CONSUMER, transport, spanBuilder, callable, this::setSpanError); + public T traceConsumerSpan( + Map transport, + SpanBuilder spanBuilder, + ThrowingSupplier throwingSupplier) + throws E { + return extractAndRun(CONSUMER, transport, spanBuilder, throwingSupplier, this::setSpanError); } /** @@ -349,38 +365,36 @@ public T traceConsumerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. * - *

If an exception is thrown by the {@link Runnable}, the handleException consumer will be - * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not - * marking the span as error. + *

If an exception is thrown by the {@link ThrowingSupplier}, the handleException consumer will + * be called, giving you the opportunity to handle the exception and span in a custom way, e.g. + * not marking the span as error. * * @param transport the transport where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use - * @param callable the {@link Callable} to call + * @param throwingSupplier the {@link ThrowingSupplier} to call * @param handleException the consumer to call when an exception is thrown * @param the type of the result - * @return the result of the {@link Callable} + * @param the type of the exception + * @return the result of the {@link ThrowingSupplier} */ - public T traceConsumerSpan( + public T traceConsumerSpan( Map transport, SpanBuilder spanBuilder, - Callable callable, - BiConsumer handleException) { - return extractAndRun(CONSUMER, transport, spanBuilder, callable, handleException); + ThrowingSupplier throwingSupplier, + BiConsumer handleException) + throws E { + return extractAndRun(CONSUMER, transport, spanBuilder, throwingSupplier, handleException); } - private T extractAndRun( + private T extractAndRun( SpanKind spanKind, Map transport, SpanBuilder spanBuilder, - Callable callable, - BiConsumer handleException) { + ThrowingSupplier throwingSupplier, + BiConsumer handleException) + throws E { try (Scope ignore = extractContext(transport).makeCurrent()) { - return call(spanBuilder.setSpanKind(spanKind), callable, handleException); + return call(spanBuilder.setSpanKind(spanKind), throwingSupplier, handleException); } } - - @SuppressWarnings("unchecked") - private static void sneakyThrow(Throwable e) throws E { - throw (E) e; - } } diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index 6b663eef4..66b3557cd 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -18,10 +18,9 @@ import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import io.opentelemetry.sdk.trace.data.StatusData; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import io.opentelemetry.semconv.SemanticAttributes; import java.util.Collections; import java.util.Map; -import java.util.concurrent.Callable; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Stream; @@ -34,6 +33,10 @@ public class TracingTest { + interface ThrowingBiConsumer { + void accept(T t, U u) throws Throwable; + } + @RegisterExtension static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); @@ -79,12 +82,12 @@ void callWithBaggage() { } private static class ExtractAndRunParameter { - private final BiConsumer> extractAndRun; + private final ThrowingBiConsumer> extractAndRun; private final SpanKind wantKind; private final StatusData wantStatus; private ExtractAndRunParameter( - BiConsumer> extractAndRun, + ThrowingBiConsumer> extractAndRun, SpanKind wantKind, StatusData wantStatus) { this.extractAndRun = extractAndRun; From 9c0cd7aaad77c62f47125cb047b2b8a03ac88db8 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 18 Sep 2023 11:46:51 +0200 Subject: [PATCH 17/33] remove non-essential parts of Tracing --- .../opentelemetry/contrib/tracer/Tracing.java | 32 ++------ .../contrib/tracer/TracingTest.java | 81 ------------------- 2 files changed, 5 insertions(+), 108 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index b5b3fea9a..c76a37f7b 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -150,7 +150,7 @@ public T call(String spanName, ThrowingSupplier t */ public T call( SpanBuilder spanBuilder, ThrowingSupplier throwingSupplier) throws E { - return call(spanBuilder, throwingSupplier, this::setSpanError); + return call(spanBuilder, throwingSupplier, Tracing::setSpanError); } /** @@ -186,39 +186,17 @@ public T call( } } - /** - * Marks a span as error. - * - * @param span the span - * @param description what went wrong - */ - public void setSpanError(Span span, String description) { - span.setStatus(StatusCode.ERROR, description); - } - /** * Marks a span as error. * * @param span the span * @param exception the exception that caused the error */ - public void setSpanError(Span span, Throwable exception) { + private static void setSpanError(Span span, Throwable exception) { 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 - */ - public void setSpanError(Span span, String description, Throwable exception) { - span.setStatus(StatusCode.ERROR, description); - span.recordException(exception); - } - /** * Injects the current context into a string map, which can then be added to HTTP headers or the * metadata of an event. @@ -245,7 +223,7 @@ public Map getPropagationHeaders() { * Extract the context from a string map, which you get from HTTP headers of the metadata of an * event you're processing. */ - public Context extractContext(Map transport) { + private Context extractContext(Map transport) { Context current = Context.current(); //noinspection ConstantConditions if (transport == null) { @@ -305,7 +283,7 @@ public T traceServerSpan( SpanBuilder spanBuilder, ThrowingSupplier throwingSupplier) throws E { - return extractAndRun(SERVER, transport, spanBuilder, throwingSupplier, this::setSpanError); + return extractAndRun(SERVER, transport, spanBuilder, throwingSupplier, Tracing::setSpanError); } /** @@ -356,7 +334,7 @@ public T traceConsumerSpan( SpanBuilder spanBuilder, ThrowingSupplier throwingSupplier) throws E { - return extractAndRun(CONSUMER, transport, spanBuilder, throwingSupplier, this::setSpanError); + return extractAndRun(CONSUMER, transport, spanBuilder, throwingSupplier, Tracing::setSpanError); } /** diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index 66b3557cd..717c9b942 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -13,18 +13,13 @@ import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import io.opentelemetry.sdk.trace.data.StatusData; -import io.opentelemetry.semconv.SemanticAttributes; import java.util.Collections; import java.util.Map; import java.util.function.BiConsumer; -import java.util.function.Consumer; import java.util.stream.Stream; -import org.assertj.core.api.AbstractCharSequenceAssert; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; @@ -50,12 +45,6 @@ void propagation() { Map propagationHeaders = tracing.getPropagationHeaders(); assertThat(propagationHeaders).hasSize(1).containsKey("traceparent"); - assertThat( - Span.fromContext(tracing.extractContext(propagationHeaders)) - .getSpanContext() - .getSpanId()) - .isEqualTo(Span.current().getSpanContext().getSpanId()); - tracing.traceServerSpan(propagationHeaders, tracing.spanBuilder("child"), () -> null); }); @@ -157,74 +146,4 @@ void extractAndRun(ExtractAndRunParameter parameter) { trace.hasSpansSatisfyingExactly( span -> span.hasKind(parameter.wantKind).hasStatus(parameter.wantStatus))); } - - private static class SetSpanErrorParameter { - private final Consumer setError; - private final String wantDescription; - private final Throwable wantException; - - private SetSpanErrorParameter( - Consumer setError, String wantDescription, Throwable wantException) { - this.setError = setError; - this.wantDescription = wantDescription; - this.wantException = wantException; - } - } - - @Keep - private static Stream setSpanError() { - Tracing tracing = new Tracing(otelTesting.getOpenTelemetry(), "test"); - RuntimeException exception = new RuntimeException("ex"); - return Stream.of( - Arguments.of( - named( - "with description", - new SetSpanErrorParameter(s -> tracing.setSpanError(s, "error"), "error", null))), - Arguments.of( - named( - "with exception", - new SetSpanErrorParameter( - s -> tracing.setSpanError(s, exception), null, exception))), - Arguments.of( - named( - "with exception and description", - new SetSpanErrorParameter( - s -> tracing.setSpanError(s, "error", exception), "error", exception)))); - } - - @ParameterizedTest - @MethodSource - void setSpanError(SetSpanErrorParameter parameter) { - tracing.run("parent", () -> parameter.setError.accept(Span.current())); - - otelTesting - .assertTraces() - .hasSize(1) - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> { - SpanDataAssert spanDataAssert = - span.hasStatus( - StatusData.create(StatusCode.ERROR, parameter.wantDescription)); - if (parameter.wantException != null) { - spanDataAssert.hasEventsSatisfyingExactly( - event -> - event.hasAttributesSatisfyingExactly( - OpenTelemetryAssertions.satisfies( - SemanticAttributes.EXCEPTION_TYPE, - s -> - s.isEqualTo( - parameter.wantException.getClass().getName())), - OpenTelemetryAssertions.satisfies( - SemanticAttributes.EXCEPTION_MESSAGE, - AbstractCharSequenceAssert::isNotBlank), - OpenTelemetryAssertions.satisfies( - SemanticAttributes.EXCEPTION_STACKTRACE, - AbstractCharSequenceAssert::isNotBlank))); - } else { - spanDataAssert.hasTotalRecordedEvents(0); - } - })); - } } From 8c59ebe60144c094d9322c4cc1da46f3a1bcdad3 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 25 Sep 2023 12:51:47 +0200 Subject: [PATCH 18/33] Update extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java Co-authored-by: Trask Stalnaker --- .../src/main/java/io/opentelemetry/contrib/tracer/Tracing.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index c76a37f7b..15ee2e4d8 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -86,7 +86,7 @@ public SpanBuilder spanBuilder(String spanName) { } /** - * Runs the given {@link Runnable} in a new span with the given name. + * Runs the given {@link Runnable} in a new span with the given name and with kind INTERNAL. * *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the * exception will be recorded. From 5c948ba590ca209c563825803fd5a175e9b6dee4 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 25 Sep 2023 12:54:08 +0200 Subject: [PATCH 19/33] Update extended-tracer/build.gradle.kts Co-authored-by: Trask Stalnaker --- extended-tracer/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/extended-tracer/build.gradle.kts b/extended-tracer/build.gradle.kts index 3f904c8fc..255485a4f 100644 --- a/extended-tracer/build.gradle.kts +++ b/extended-tracer/build.gradle.kts @@ -13,5 +13,4 @@ otelJava { dependencies { api("io.opentelemetry:opentelemetry-api") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") - testImplementation("io.opentelemetry.semconv:opentelemetry-semconv") } From 13c3819b0119de6cbb1472e1c0274e103b65016b Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 25 Sep 2023 12:55:25 +0200 Subject: [PATCH 20/33] Update extended-tracer/build.gradle.kts Co-authored-by: Trask Stalnaker --- extended-tracer/build.gradle.kts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/extended-tracer/build.gradle.kts b/extended-tracer/build.gradle.kts index 255485a4f..f4b6f63ce 100644 --- a/extended-tracer/build.gradle.kts +++ b/extended-tracer/build.gradle.kts @@ -6,10 +6,6 @@ plugins { description = "Tracing Utilities" otelJava.moduleName.set("io.opentelemetry.contrib.extended-tracer") -otelJava { - minJavaVersionSupported.set(JavaVersion.VERSION_1_8) -} - dependencies { api("io.opentelemetry:opentelemetry-api") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") From 12dccfaa019c603d25a2fc19943ae041b146a20e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 25 Sep 2023 12:55:42 +0200 Subject: [PATCH 21/33] Update extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java Co-authored-by: Trask Stalnaker --- .../io/opentelemetry/contrib/tracer/ThrowingSupplier.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java index bd25c7a61..bddd30717 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java @@ -13,6 +13,6 @@ * @param Thrown exception type. */ @FunctionalInterface -public interface ThrowingSupplier { - T get() throws E; +public interface SpanCallback { + T doInSpan() throws E; } From c0604045822f3b4d0701bb0bbbdf2429dd70f1fa Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 25 Sep 2023 13:04:23 +0200 Subject: [PATCH 22/33] rename ThrowingSupplier to SpanCallback --- ...hrowingSupplier.java => SpanCallback.java} | 0 .../opentelemetry/contrib/tracer/Tracing.java | 120 +++++++++--------- .../contrib/tracer/TracingTest.java | 4 +- 3 files changed, 60 insertions(+), 64 deletions(-) rename extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/{ThrowingSupplier.java => SpanCallback.java} (100%) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanCallback.java similarity index 100% rename from extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/ThrowingSupplier.java rename to extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanCallback.java diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index 15ee2e4d8..fc0702eab 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -119,65 +119,65 @@ public void run(SpanBuilder spanBuilder, Runnable runnable) { } /** - * Runs the given {@link ThrowingSupplier} inside a new span with the given name. + * Runs the given {@link SpanCallback} inside a new span with the given name. * - *

If an exception is thrown by the {@link ThrowingSupplier}, the span will be marked as error, - * and the exception will be recorded. + *

If an exception is thrown by the {@link SpanCallback}, the span will be marked as error, and + * the exception will be recorded. * * @param spanName the name of the span - * @param throwingSupplier the {@link ThrowingSupplier} to call + * @param spanCallback the {@link SpanCallback} to call * @param the type of the result * @param the type of the exception - * @return the result of the {@link ThrowingSupplier} + * @return the result of the {@link SpanCallback} */ - public T call(String spanName, ThrowingSupplier throwingSupplier) + public T call(String spanName, SpanCallback spanCallback) throws E { - return call(tracer.spanBuilder(spanName), throwingSupplier); + return call(tracer.spanBuilder(spanName), spanCallback); } /** - * Runs the given {@link ThrowingSupplier} inside of the span created by the given {@link - * SpanBuilder}. The span will be ended at the end of the {@link ThrowingSupplier}. + * Runs the given {@link SpanCallback} inside of the span created by the given {@link + * SpanBuilder}. The span will be ended at the end of the {@link SpanCallback}. * - *

If an exception is thrown by the {@link ThrowingSupplier}, the span will be marked as error, - * and the exception will be recorded. + *

If an exception is thrown by the {@link SpanCallback}, the span will be marked as error, and + * the exception will be recorded. * * @param spanBuilder the {@link SpanBuilder} to use - * @param throwingSupplier the {@link ThrowingSupplier} to call + * @param spanCallback the {@link SpanCallback} to call * @param the type of the result * @param the type of the exception - * @return the result of the {@link ThrowingSupplier} + * @return the result of the {@link SpanCallback} */ - public T call( - SpanBuilder spanBuilder, ThrowingSupplier throwingSupplier) throws E { - return call(spanBuilder, throwingSupplier, Tracing::setSpanError); + public T call(SpanBuilder spanBuilder, SpanCallback spanCallback) + throws E { + return call(spanBuilder, spanCallback, Tracing::setSpanError); } /** - * Runs the given {@link ThrowingSupplier} inside of the span created by the given {@link - * SpanBuilder}. The span will be ended at the end of the {@link ThrowingSupplier}. + * Runs the given {@link SpanCallback} inside of the span created by the given {@link + * SpanBuilder}. The span will be ended at the end of the {@link SpanCallback}. * - *

If an exception is thrown by the {@link ThrowingSupplier}, the handleException consumer will - * be called, giving you the opportunity to handle the exception and span in a custom way, e.g. - * not marking the span as error. + *

If an exception is thrown by the {@link SpanCallback}, the handleException consumer will be + * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not + * marking the span as error. * * @param spanBuilder the {@link SpanBuilder} to use - * @param throwingSupplier the {@link ThrowingSupplier} to call + * @param spanCallback the {@link SpanCallback} to call * @param handleException the consumer to call when an exception is thrown * @param the type of the result * @param the type of the exception - * @return the result of the {@link ThrowingSupplier} + * @return the result of the {@link SpanCallback} */ @SuppressWarnings("NullAway") public T call( SpanBuilder spanBuilder, - ThrowingSupplier throwingSupplier, + SpanCallback spanCallback, BiConsumer handleException) throws E { Span span = spanBuilder.startSpan(); //noinspection unused try (Scope unused = span.makeCurrent()) { - return throwingSupplier.get(); + return spanCallback.doInSpan(); } catch (Throwable e) { handleException.accept(span, e); throw e; @@ -243,22 +243,22 @@ private Context extractContext(Map transport) { } /** - * Set baggage items inside the given {@link ThrowingSupplier}. + * Set baggage items inside the given {@link SpanCallback}. * * @param baggage the baggage items to set - * @param throwingSupplier the {@link ThrowingSupplier} to call + * @param spanCallback the {@link SpanCallback} to call * @param the type of the result * @param the type of the exception - * @return the result of the {@link ThrowingSupplier} + * @return the result of the {@link SpanCallback} */ @SuppressWarnings("NullAway") public T callWithBaggage( - Map baggage, ThrowingSupplier throwingSupplier) throws E { + Map baggage, SpanCallback spanCallback) throws E { BaggageBuilder builder = Baggage.current().toBuilder(); baggage.forEach(builder::put); Context context = builder.build().storeInContext(Context.current()); try (Scope ignore = context.makeCurrent()) { - return throwingSupplier.get(); + return spanCallback.doInSpan(); } } @@ -268,22 +268,20 @@ public T callWithBaggage( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. * - *

If an exception is thrown by the {@link ThrowingSupplier}, the span will be marked as error, - * and the exception will be recorded. + *

If an exception is thrown by the {@link SpanCallback}, the span will be marked as error, and + * the exception will be recorded. * * @param transport the transport where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use - * @param throwingSupplier the {@link ThrowingSupplier} to call + * @param spanCallback the {@link SpanCallback} to call * @param the type of the result * @param the type of the exception - * @return the result of the {@link ThrowingSupplier} + * @return the result of the {@link SpanCallback} */ public T traceServerSpan( - Map transport, - SpanBuilder spanBuilder, - ThrowingSupplier throwingSupplier) + Map transport, SpanBuilder spanBuilder, SpanCallback spanCallback) throws E { - return extractAndRun(SERVER, transport, spanBuilder, throwingSupplier, Tracing::setSpanError); + return extractAndRun(SERVER, transport, spanBuilder, spanCallback, Tracing::setSpanError); } /** @@ -292,25 +290,25 @@ public T traceServerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. * - *

If an exception is thrown by the {@link ThrowingSupplier}, the handleException consumer will - * be called, giving you the opportunity to handle the exception and span in a custom way, e.g. - * not marking the span as error. + *

If an exception is thrown by the {@link SpanCallback}, the handleException consumer will be + * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not + * marking the span as error. * * @param transport the transport where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use - * @param throwingSupplier the {@link ThrowingSupplier} to call + * @param spanCallback the {@link SpanCallback} to call * @param handleException the consumer to call when an exception is thrown * @param the type of the result * @param the type of the exception - * @return the result of the {@link ThrowingSupplier} + * @return the result of the {@link SpanCallback} */ public T traceServerSpan( Map transport, SpanBuilder spanBuilder, - ThrowingSupplier throwingSupplier, + SpanCallback spanCallback, BiConsumer handleException) throws E { - return extractAndRun(SERVER, transport, spanBuilder, throwingSupplier, handleException); + return extractAndRun(SERVER, transport, spanBuilder, spanCallback, handleException); } /** @@ -319,22 +317,20 @@ public T traceServerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. * - *

If an exception is thrown by the {@link ThrowingSupplier}, the span will be marked as error, - * and the exception will be recorded. + *

If an exception is thrown by the {@link SpanCallback}, the span will be marked as error, and + * the exception will be recorded. * * @param transport the transport where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use - * @param throwingSupplier the {@link ThrowingSupplier} to call + * @param spanCallback the {@link SpanCallback} to call * @param the type of the result * @param the type of the exception - * @return the result of the {@link ThrowingSupplier} + * @return the result of the {@link SpanCallback} */ public T traceConsumerSpan( - Map transport, - SpanBuilder spanBuilder, - ThrowingSupplier throwingSupplier) + Map transport, SpanBuilder spanBuilder, SpanCallback spanCallback) throws E { - return extractAndRun(CONSUMER, transport, spanBuilder, throwingSupplier, Tracing::setSpanError); + return extractAndRun(CONSUMER, transport, spanBuilder, spanCallback, Tracing::setSpanError); } /** @@ -343,36 +339,36 @@ public T traceConsumerSpan( *

The span context will be extracted from the transport, which you usually get * from HTTP headers of the metadata of an event you're processing. * - *

If an exception is thrown by the {@link ThrowingSupplier}, the handleException consumer will - * be called, giving you the opportunity to handle the exception and span in a custom way, e.g. - * not marking the span as error. + *

If an exception is thrown by the {@link SpanCallback}, the handleException consumer will be + * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not + * marking the span as error. * * @param transport the transport where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use - * @param throwingSupplier the {@link ThrowingSupplier} to call + * @param spanCallback the {@link SpanCallback} to call * @param handleException the consumer to call when an exception is thrown * @param the type of the result * @param the type of the exception - * @return the result of the {@link ThrowingSupplier} + * @return the result of the {@link SpanCallback} */ public T traceConsumerSpan( Map transport, SpanBuilder spanBuilder, - ThrowingSupplier throwingSupplier, + SpanCallback spanCallback, BiConsumer handleException) throws E { - return extractAndRun(CONSUMER, transport, spanBuilder, throwingSupplier, handleException); + return extractAndRun(CONSUMER, transport, spanBuilder, spanCallback, handleException); } private T extractAndRun( SpanKind spanKind, Map transport, SpanBuilder spanBuilder, - ThrowingSupplier throwingSupplier, + SpanCallback spanCallback, BiConsumer handleException) throws E { try (Scope ignore = extractContext(transport).makeCurrent()) { - return call(spanBuilder.setSpanKind(spanKind), throwingSupplier, handleException); + return call(spanBuilder.setSpanKind(spanKind), spanCallback, handleException); } } } diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index 717c9b942..d9f8f31c8 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -71,12 +71,12 @@ void callWithBaggage() { } private static class ExtractAndRunParameter { - private final ThrowingBiConsumer> extractAndRun; + private final ThrowingBiConsumer> extractAndRun; private final SpanKind wantKind; private final StatusData wantStatus; private ExtractAndRunParameter( - ThrowingBiConsumer> extractAndRun, + ThrowingBiConsumer> extractAndRun, SpanKind wantKind, StatusData wantStatus) { this.extractAndRun = extractAndRun; From b0500babe12a04ff9d89390951ebe2289393ea35 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 2 Oct 2023 12:18:27 +0200 Subject: [PATCH 23/33] Update extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java Co-authored-by: Trask Stalnaker --- .../src/main/java/io/opentelemetry/contrib/tracer/Tracing.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index fc0702eab..d8af8bb52 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -60,7 +60,7 @@ public String get(@Nullable Map carrier, String key) { * @param openTelemetry the {@link OpenTelemetry} instance * @param tracerName the name of the tracer to use */ - public Tracing(OpenTelemetry openTelemetry, String tracerName) { + public Tracing(OpenTelemetry openTelemetry, String instrumentationScopeName) { this(openTelemetry, openTelemetry.getTracer(tracerName)); } From bb9e70421e523936c3b73656c0200a800e04151e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 2 Oct 2023 12:30:45 +0200 Subject: [PATCH 24/33] rename transport to carrier --- .../opentelemetry/contrib/tracer/Tracing.java | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index d8af8bb52..74a0feb24 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -58,10 +58,10 @@ public String get(@Nullable Map carrier, String key) { * Creates a new instance of {@link Tracing}. * * @param openTelemetry the {@link OpenTelemetry} instance - * @param tracerName the name of the tracer to use + * @param instrumentationScopeName the name of the tracer to use */ public Tracing(OpenTelemetry openTelemetry, String instrumentationScopeName) { - this(openTelemetry, openTelemetry.getTracer(tracerName)); + this(openTelemetry, openTelemetry.getTracer(instrumentationScopeName)); } /** @@ -202,44 +202,46 @@ private static void setSpanError(Span span, Throwable exception) { * metadata of an event. */ public Map getPropagationHeaders() { - Map transport = new HashMap<>(); + Map carrier = new HashMap<>(); //noinspection ConstantConditions openTelemetry .getPropagators() .getTextMapPropagator() .inject( Context.current(), - transport, + carrier, (map, key, value) -> { if (map != null) { map.put(key, value); } }); - return transport; + return carrier; } /** * Extract the context from a string map, which you get from HTTP headers of the metadata of an * event you're processing. + * + * @param carrier the string map */ - private Context extractContext(Map transport) { + private Context extractContext(Map carrier) { Context current = Context.current(); //noinspection ConstantConditions - if (transport == null) { + if (carrier == null) { return current; } // HTTP headers are case-insensitive. As we're using Map, which is case-sensitive, we need to // normalize all the keys - Map normalizedTransport = - transport.entrySet().stream() + Map normalizedCarrier = + carrier.entrySet().stream() .collect( Collectors.toMap( entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue)); return openTelemetry .getPropagators() .getTextMapPropagator() - .extract(current, normalizedTransport, TEXT_MAP_GETTER); + .extract(current, normalizedCarrier, TEXT_MAP_GETTER); } /** @@ -265,13 +267,13 @@ public T callWithBaggage( /** * Run the given {@link Runnable} inside a server span. * - *

The span context will be extracted from the transport, which you usually get + *

The span context will be extracted from the carrier, which you usually get * from HTTP headers of the metadata of an event you're processing. * *

If an exception is thrown by the {@link SpanCallback}, the span will be marked as error, and * the exception will be recorded. * - * @param transport the transport where to extract the span context from + * @param carrier the string map where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use * @param spanCallback the {@link SpanCallback} to call * @param the type of the result @@ -279,22 +281,22 @@ public T callWithBaggage( * @return the result of the {@link SpanCallback} */ public T traceServerSpan( - Map transport, SpanBuilder spanBuilder, SpanCallback spanCallback) + Map carrier, SpanBuilder spanBuilder, SpanCallback spanCallback) throws E { - return extractAndRun(SERVER, transport, spanBuilder, spanCallback, Tracing::setSpanError); + return extractAndRun(SERVER, carrier, spanBuilder, spanCallback, Tracing::setSpanError); } /** * Run the given {@link Runnable} inside a server span. * - *

The span context will be extracted from the transport, which you usually get + *

The span context will be extracted from the carrier, which you usually get * from HTTP headers of the metadata of an event you're processing. * *

If an exception is thrown by the {@link SpanCallback}, the handleException consumer will be * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not * marking the span as error. * - * @param transport the transport where to extract the span context from + * @param carrier the string map where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use * @param spanCallback the {@link SpanCallback} to call * @param handleException the consumer to call when an exception is thrown @@ -303,24 +305,24 @@ public T traceServerSpan( * @return the result of the {@link SpanCallback} */ public T traceServerSpan( - Map transport, + Map carrier, SpanBuilder spanBuilder, SpanCallback spanCallback, BiConsumer handleException) throws E { - return extractAndRun(SERVER, transport, spanBuilder, spanCallback, handleException); + return extractAndRun(SERVER, carrier, spanBuilder, spanCallback, handleException); } /** * Run the given {@link Runnable} inside a server span. * - *

The span context will be extracted from the transport, which you usually get + *

The span context will be extracted from the carrier, which you usually get * from HTTP headers of the metadata of an event you're processing. * *

If an exception is thrown by the {@link SpanCallback}, the span will be marked as error, and * the exception will be recorded. * - * @param transport the transport where to extract the span context from + * @param carrier the string map where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use * @param spanCallback the {@link SpanCallback} to call * @param the type of the result @@ -328,22 +330,22 @@ public T traceServerSpan( * @return the result of the {@link SpanCallback} */ public T traceConsumerSpan( - Map transport, SpanBuilder spanBuilder, SpanCallback spanCallback) + Map carrier, SpanBuilder spanBuilder, SpanCallback spanCallback) throws E { - return extractAndRun(CONSUMER, transport, spanBuilder, spanCallback, Tracing::setSpanError); + return extractAndRun(CONSUMER, carrier, spanBuilder, spanCallback, Tracing::setSpanError); } /** * Run the given {@link Runnable} inside a consumer span. * - *

The span context will be extracted from the transport, which you usually get + *

The span context will be extracted from the carrier, which you usually get * from HTTP headers of the metadata of an event you're processing. * *

If an exception is thrown by the {@link SpanCallback}, the handleException consumer will be * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not * marking the span as error. * - * @param transport the transport where to extract the span context from + * @param carrier the string map where to extract the span context from * @param spanBuilder the {@link SpanBuilder} to use * @param spanCallback the {@link SpanCallback} to call * @param handleException the consumer to call when an exception is thrown @@ -352,22 +354,22 @@ public T traceConsumerSpan( * @return the result of the {@link SpanCallback} */ public T traceConsumerSpan( - Map transport, + Map carrier, SpanBuilder spanBuilder, SpanCallback spanCallback, BiConsumer handleException) throws E { - return extractAndRun(CONSUMER, transport, spanBuilder, spanCallback, handleException); + return extractAndRun(CONSUMER, carrier, spanBuilder, spanCallback, handleException); } private T extractAndRun( SpanKind spanKind, - Map transport, + Map carrier, SpanBuilder spanBuilder, SpanCallback spanCallback, BiConsumer handleException) throws E { - try (Scope ignore = extractContext(transport).makeCurrent()) { + try (Scope ignore = extractContext(carrier).makeCurrent()) { return call(spanBuilder.setSpanKind(spanKind), spanCallback, handleException); } } From afbefa0d7721cc8edbd5f073025ab4bf0fc8165e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 4 Oct 2023 17:50:24 +0200 Subject: [PATCH 25/33] add SpanRunnable similar to SpanCallback --- .../contrib/tracer/SpanRunnable.java | 16 ++++++ .../opentelemetry/contrib/tracer/Tracing.java | 49 ++++++++++--------- 2 files changed, 41 insertions(+), 24 deletions(-) create mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanRunnable.java diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanRunnable.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanRunnable.java new file mode 100644 index 000000000..d8c8b1667 --- /dev/null +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanRunnable.java @@ -0,0 +1,16 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.tracer; + +/** + * A utility interface representing a {@link Runnable} that may throw. + * + * @param Thrown exception type. + */ +@FunctionalInterface +public interface SpanRunnable { + void doInSpan() throws E; +} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index 74a0feb24..866439b9b 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -86,34 +86,35 @@ public SpanBuilder spanBuilder(String spanName) { } /** - * Runs the given {@link Runnable} in a new span with the given name and with kind INTERNAL. + * Runs the given {@link SpanRunnable} in a new span with the given name and with kind INTERNAL. * - *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the - * exception will be recorded. + *

If an exception is thrown by the {@link SpanRunnable}, the span will be marked as error, and + * the exception will be recorded. * * @param spanName the name of the span - * @param runnable the {@link Runnable} to run + * @param runnable the {@link SpanRunnable} to run */ - public void run(String spanName, Runnable runnable) { + public void run(String spanName, SpanRunnable runnable) throws E { run(tracer.spanBuilder(spanName), runnable); } /** - * Runs the given {@link Runnable} inside of the span created by the given {@link SpanBuilder}. - * The span will be ended at the end of the {@link Runnable}. + * Runs the given {@link SpanRunnable} inside of the span created by the given {@link + * SpanBuilder}. The span will be ended at the end of the {@link SpanRunnable}. * - *

If an exception is thrown by the {@link Runnable}, the span will be marked as error, and the - * exception will be recorded. + *

If an exception is thrown by the {@link SpanRunnable}, the span will be marked as error, and + * the exception will be recorded. * * @param spanBuilder the {@link SpanBuilder} to use - * @param runnable the {@link Runnable} to run + * @param runnable the {@link SpanRunnable} to run */ @SuppressWarnings("NullAway") - public void run(SpanBuilder spanBuilder, Runnable runnable) { + public void run(SpanBuilder spanBuilder, SpanRunnable runnable) + throws E { call( spanBuilder, () -> { - runnable.run(); + runnable.doInSpan(); return null; }); } @@ -265,10 +266,10 @@ public T callWithBaggage( } /** - * Run the given {@link Runnable} inside a server span. + * Run the given {@link SpanCallback} inside a server span. * - *

The span context will be extracted from the carrier, which you usually get - * from HTTP headers of the metadata of an event you're processing. + *

The span context will be extracted from the carrier, which you usually get from + * HTTP headers of the metadata of an event you're processing. * *

If an exception is thrown by the {@link SpanCallback}, the span will be marked as error, and * the exception will be recorded. @@ -287,10 +288,10 @@ public T traceServerSpan( } /** - * Run the given {@link Runnable} inside a server span. + * Run the given {@link SpanCallback} inside a server span. * - *

The span context will be extracted from the carrier, which you usually get - * from HTTP headers of the metadata of an event you're processing. + *

The span context will be extracted from the carrier, which you usually get from + * HTTP headers of the metadata of an event you're processing. * *

If an exception is thrown by the {@link SpanCallback}, the handleException consumer will be * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not @@ -314,10 +315,10 @@ public T traceServerSpan( } /** - * Run the given {@link Runnable} inside a server span. + * Run the given {@link SpanCallback} inside a server span. * - *

The span context will be extracted from the carrier, which you usually get - * from HTTP headers of the metadata of an event you're processing. + *

The span context will be extracted from the carrier, which you usually get from + * HTTP headers of the metadata of an event you're processing. * *

If an exception is thrown by the {@link SpanCallback}, the span will be marked as error, and * the exception will be recorded. @@ -336,10 +337,10 @@ public T traceConsumerSpan( } /** - * Run the given {@link Runnable} inside a consumer span. + * Run the given {@link SpanRunnable} inside a consumer span. * - *

The span context will be extracted from the carrier, which you usually get - * from HTTP headers of the metadata of an event you're processing. + *

The span context will be extracted from the carrier, which you usually get from + * HTTP headers of the metadata of an event you're processing. * *

If an exception is thrown by the {@link SpanCallback}, the handleException consumer will be * called, giving you the opportunity to handle the exception and span in a custom way, e.g. not From a26443644cb3e25ac6730adf8e1069cadcfd12f7 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 4 Oct 2023 17:52:51 +0200 Subject: [PATCH 26/33] rename propagation methods --- .../main/java/io/opentelemetry/contrib/tracer/Tracing.java | 6 +++--- .../java/io/opentelemetry/contrib/tracer/TracingTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index 866439b9b..ed5587bd9 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -202,7 +202,7 @@ private static void setSpanError(Span span, Throwable exception) { * Injects the current context into a string map, which can then be added to HTTP headers or the * metadata of an event. */ - public Map getPropagationHeaders() { + public Map getTextMapPropagationContext() { Map carrier = new HashMap<>(); //noinspection ConstantConditions openTelemetry @@ -226,7 +226,7 @@ public Map getPropagationHeaders() { * * @param carrier the string map */ - private Context extractContext(Map carrier) { + private Context extractTextMapPropagationContext(Map carrier) { Context current = Context.current(); //noinspection ConstantConditions if (carrier == null) { @@ -370,7 +370,7 @@ private T extractAndRun( SpanCallback spanCallback, BiConsumer handleException) throws E { - try (Scope ignore = extractContext(carrier).makeCurrent()) { + try (Scope ignore = extractTextMapPropagationContext(carrier).makeCurrent()) { return call(spanBuilder.setSpanKind(spanKind), spanCallback, handleException); } } diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index d9f8f31c8..d63b102a3 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -42,7 +42,7 @@ void propagation() { tracing.run( "parent", () -> { - Map propagationHeaders = tracing.getPropagationHeaders(); + Map propagationHeaders = tracing.getTextMapPropagationContext(); assertThat(propagationHeaders).hasSize(1).containsKey("traceparent"); tracing.traceServerSpan(propagationHeaders, tracing.spanBuilder("child"), () -> null); From 18ed800063ab63cff88274cce47694990afc506d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 5 Oct 2023 08:55:56 +0200 Subject: [PATCH 27/33] add SpanRunnable similar to SpanCallback --- .../java/io/opentelemetry/contrib/tracer/SpanCallback.java | 6 +++--- .../java/io/opentelemetry/contrib/tracer/SpanRunnable.java | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanCallback.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanCallback.java index bddd30717..d39e9e631 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanCallback.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanCallback.java @@ -5,10 +5,10 @@ package io.opentelemetry.contrib.tracer; -import java.util.function.Supplier; - /** - * A utility interface representing a {@link Supplier} that may throw. + * An interface for creating a lambda that is wrapped in a span, returns a value, and that may + * throw, similar to TransactionCallback. * * @param Thrown exception type. */ diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanRunnable.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanRunnable.java index d8c8b1667..0e440726d 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanRunnable.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/SpanRunnable.java @@ -6,7 +6,8 @@ package io.opentelemetry.contrib.tracer; /** - * A utility interface representing a {@link Runnable} that may throw. + * An interface for creating a lambda that is wrapped in a span and that may throw, similar to TransactionCallback. * * @param Thrown exception type. */ From ad1b988586cccef9a7e99e5c980b4cda2fc6c859 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 5 Oct 2023 09:55:06 +0200 Subject: [PATCH 28/33] add more tests to show usage --- extended-tracer/build.gradle.kts | 1 + .../contrib/tracer/TracingTest.java | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/extended-tracer/build.gradle.kts b/extended-tracer/build.gradle.kts index f4b6f63ce..8eafcab33 100644 --- a/extended-tracer/build.gradle.kts +++ b/extended-tracer/build.gradle.kts @@ -9,4 +9,5 @@ otelJava.moduleName.set("io.opentelemetry.contrib.extended-tracer") dependencies { api("io.opentelemetry:opentelemetry-api") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") + testImplementation("io.opentelemetry.semconv:opentelemetry-semconv") } diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index d63b102a3..7d0b7de35 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -7,15 +7,18 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatException; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.junit.jupiter.api.Named.named; import com.google.errorprone.annotations.Keep; import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.semconv.SemanticAttributes; import java.util.Collections; import java.util.Map; import java.util.function.BiConsumer; @@ -37,6 +40,54 @@ interface ThrowingBiConsumer { private final Tracing tracing = new Tracing(otelTesting.getOpenTelemetry(), "test"); + @Test + void wrapInSpan() { + assertThatIllegalStateException() + .isThrownBy( + () -> + tracing.run( + "test", + () -> { + // runs in span + throw new IllegalStateException("ex"); + })); + + String result = + tracing.call( + "another test", + () -> { + // runs in span + return "result"; + }); + assertThat(result).isEqualTo("result"); + + otelTesting + .assertTraces() + .hasSize(2) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("test") + .hasStatus(StatusData.error()) + .hasEventsSatisfyingExactly( + event -> + event + .hasName("exception") + .hasAttributesSatisfyingExactly( + OpenTelemetryAssertions.equalTo( + SemanticAttributes.EXCEPTION_TYPE, + "java.lang.IllegalStateException"), + OpenTelemetryAssertions.satisfies( + SemanticAttributes.EXCEPTION_STACKTRACE, + string -> + string.contains( + "java.lang.IllegalStateException: ex")), + OpenTelemetryAssertions.equalTo( + SemanticAttributes.EXCEPTION_MESSAGE, "ex")))), + trace -> trace.hasSpansSatisfyingExactly(a -> a.hasName("another test"))); + } + @Test void propagation() { tracing.run( From 7cd4616339bb8822c2dca1277df0a057912c18c6 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 6 Oct 2023 12:09:18 +0200 Subject: [PATCH 29/33] - make callWithBaggage static - extract Propagation class with static methods --- .../contrib/tracer/Propagation.java | 82 +++++++++++++++++++ .../opentelemetry/contrib/tracer/Tracing.java | 66 +-------------- 2 files changed, 86 insertions(+), 62 deletions(-) create mode 100644 extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Propagation.java diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Propagation.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Propagation.java new file mode 100644 index 000000000..d8713ab24 --- /dev/null +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Propagation.java @@ -0,0 +1,82 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.tracer; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapGetter; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nullable; + +public class Propagation { + + private static final TextMapGetter> TEXT_MAP_GETTER = + new TextMapGetter>() { + @Override + public Set keys(Map carrier) { + return carrier.keySet(); + } + + @Override + @Nullable + public String get(@Nullable Map carrier, String key) { + //noinspection ConstantConditions + return carrier == null ? null : carrier.get(key); + } + }; + + /** + * Injects the current context into a string map, which can then be added to HTTP headers or the + * metadata of an event. + */ + public static Map getTextMapPropagationContext(OpenTelemetry openTelemetry) { + Map carrier = new HashMap<>(); + //noinspection ConstantConditions + openTelemetry + .getPropagators() + .getTextMapPropagator() + .inject( + Context.current(), + carrier, + (map, key, value) -> { + if (map != null) { + map.put(key, value); + } + }); + + return carrier; + } + + /** + * Extract the context from a string map, which you get from HTTP headers of the metadata of an + * event you're processing. + * + * @param carrier the string map + */ + static Context extractTextMapPropagationContext( + OpenTelemetry openTelemetry, Map carrier) { + Context current = Context.current(); + //noinspection ConstantConditions + if (carrier == null) { + return current; + } + // HTTP headers are case-insensitive. As we're using Map, which is case-sensitive, we need to + // normalize all the keys + Map normalizedCarrier = + carrier.entrySet().stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue)); + return openTelemetry + .getPropagators() + .getTextMapPropagator() + .extract(current, normalizedCarrier, TEXT_MAP_GETTER); + } +} diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java index ed5587bd9..d868900d4 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Tracing.java @@ -18,14 +18,8 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.context.propagation.TextMapGetter; -import java.util.HashMap; -import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.function.BiConsumer; -import java.util.stream.Collectors; -import javax.annotation.Nullable; /** * Utility class to simplify tracing. @@ -36,20 +30,6 @@ */ public final class Tracing { - private static final TextMapGetter> TEXT_MAP_GETTER = - new TextMapGetter>() { - @Override - public Set keys(Map carrier) { - return carrier.keySet(); - } - - @Override - @Nullable - public String get(@Nullable Map carrier, String key) { - //noinspection ConstantConditions - return carrier == null ? null : carrier.get(key); - } - }; private final OpenTelemetry openTelemetry; private final Tracer tracer; @@ -203,46 +183,7 @@ private static void setSpanError(Span span, Throwable exception) { * metadata of an event. */ public Map getTextMapPropagationContext() { - Map carrier = new HashMap<>(); - //noinspection ConstantConditions - openTelemetry - .getPropagators() - .getTextMapPropagator() - .inject( - Context.current(), - carrier, - (map, key, value) -> { - if (map != null) { - map.put(key, value); - } - }); - - return carrier; - } - - /** - * Extract the context from a string map, which you get from HTTP headers of the metadata of an - * event you're processing. - * - * @param carrier the string map - */ - private Context extractTextMapPropagationContext(Map carrier) { - Context current = Context.current(); - //noinspection ConstantConditions - if (carrier == null) { - return current; - } - // HTTP headers are case-insensitive. As we're using Map, which is case-sensitive, we need to - // normalize all the keys - Map normalizedCarrier = - carrier.entrySet().stream() - .collect( - Collectors.toMap( - entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue)); - return openTelemetry - .getPropagators() - .getTextMapPropagator() - .extract(current, normalizedCarrier, TEXT_MAP_GETTER); + return Propagation.getTextMapPropagationContext(openTelemetry); } /** @@ -255,7 +196,7 @@ private Context extractTextMapPropagationContext(Map carrier) { * @return the result of the {@link SpanCallback} */ @SuppressWarnings("NullAway") - public T callWithBaggage( + public static T callWithBaggage( Map baggage, SpanCallback spanCallback) throws E { BaggageBuilder builder = Baggage.current().toBuilder(); baggage.forEach(builder::put); @@ -370,7 +311,8 @@ private T extractAndRun( SpanCallback spanCallback, BiConsumer handleException) throws E { - try (Scope ignore = extractTextMapPropagationContext(carrier).makeCurrent()) { + try (Scope ignore = + Propagation.extractTextMapPropagationContext(openTelemetry, carrier).makeCurrent()) { return call(spanBuilder.setSpanKind(spanKind), spanCallback, handleException); } } From 68e1b5c3164ee82314ace9651fe49d758d859ab9 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 12 Oct 2023 08:02:06 +0200 Subject: [PATCH 30/33] - make callWithBaggage static - extract Propagation class with static methods --- extended-tracer/README.md | 2 +- .../io/opentelemetry/contrib/tracer/Propagation.java | 11 ++++++++++- .../io/opentelemetry/contrib/tracer/TracingTest.java | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/extended-tracer/README.md b/extended-tracer/README.md index 351d62e2c..4fcb0501e 100644 --- a/extended-tracer/README.md +++ b/extended-tracer/README.md @@ -146,7 +146,7 @@ After: ```java Tracing tracing = new Tracing(openTelemetry, "service"); -String value = tracing.callWithBaggage( +String value = Tracing.callWithBaggage( Collections.singletonMap("key", "value"), () -> Baggage.current().getEntryValue("key")) ``` diff --git a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Propagation.java b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Propagation.java index d8713ab24..66c9f84be 100644 --- a/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Propagation.java +++ b/extended-tracer/src/main/java/io/opentelemetry/contrib/tracer/Propagation.java @@ -15,7 +15,16 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; -public class Propagation { +/** + * Utility class to simplify context propagation. + * + *

The README + * explains the use cases in more detail. + */ +public final class Propagation { + + private Propagation() {} private static final TextMapGetter> TEXT_MAP_GETTER = new TextMapGetter>() { diff --git a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java index 7d0b7de35..582582b36 100644 --- a/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java +++ b/extended-tracer/src/test/java/io/opentelemetry/contrib/tracer/TracingTest.java @@ -114,7 +114,7 @@ void callWithBaggage() { tracing.call( "parent", () -> - tracing.callWithBaggage( + Tracing.callWithBaggage( Collections.singletonMap("key", "value"), () -> Baggage.current().getEntryValue("key"))); From 07e55dde0908bc45521ff9062a32a1b2f0a0c79c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 26 Oct 2023 18:14:11 +0200 Subject: [PATCH 31/33] - make callWithBaggage static - extract Propagation class with static methods --- extended-tracer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extended-tracer/README.md b/extended-tracer/README.md index 4fcb0501e..78f20f455 100644 --- a/extended-tracer/README.md +++ b/extended-tracer/README.md @@ -108,7 +108,7 @@ After: ```java Tracing tracing = new Tracing(openTelemetry, "service"); -Map propagationHeaders = tracing.getPropagationHeaders(); +Map propagationHeaders = tracing.getTextMapPropagationContext(); // add propagationHeaders to request headers and call checkout service ``` From c6e0b9cfb625017101a8ff8c648dee8acd028d59 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 1 Nov 2023 09:56:53 +0100 Subject: [PATCH 32/33] Update extended-tracer/build.gradle.kts Co-authored-by: Trask Stalnaker --- extended-tracer/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extended-tracer/build.gradle.kts b/extended-tracer/build.gradle.kts index 8eafcab33..6616e9483 100644 --- a/extended-tracer/build.gradle.kts +++ b/extended-tracer/build.gradle.kts @@ -3,7 +3,7 @@ plugins { id("otel.publish-conventions") } -description = "Tracing Utilities" +description = "Extended Tracer" otelJava.moduleName.set("io.opentelemetry.contrib.extended-tracer") dependencies { From 11f07bf299a41ca505910aa3c2b17445324353b6 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 6 Nov 2023 12:18:03 +0100 Subject: [PATCH 33/33] Update extended-tracer/build.gradle.kts Co-authored-by: Trask Stalnaker --- extended-tracer/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/extended-tracer/build.gradle.kts b/extended-tracer/build.gradle.kts index 6616e9483..af1ac258c 100644 --- a/extended-tracer/build.gradle.kts +++ b/extended-tracer/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("otel.java-conventions") - id("otel.publish-conventions") } description = "Extended Tracer"