From f8ea9bb4107eddb34324d9baf74737da470f4294 Mon Sep 17 00:00:00 2001 From: Zoe Date: Wed, 21 Oct 2020 09:55:06 +1100 Subject: [PATCH] Add Support for Opencensus to OpenTelemetry migration (#2059) --- .../io/opencensus/trace/ContextHandle.java | 24 ++++++ .../io/opencensus/trace/ContextManager.java | 26 ++++++ .../io/opencensus/trace/CurrentSpanUtils.java | 26 +++--- .../java/io/opencensus/trace/Tracing.java | 16 ++++ .../trace/unsafe/ContextHandleImpl.java | 45 +++++++++++ .../trace/unsafe/ContextHandleUtils.java | 79 +++++++++++++++++++ .../trace/unsafe/ContextManagerImpl.java | 52 ++++++++++++ .../opencensus/trace/unsafe/ContextUtils.java | 2 +- .../trace/CurrentSpanUtilsTest.java | 8 +- .../trace/unsafe/ContextUtilsTest.java | 11 +-- contrib/log_correlation/log4j2/README.md | 2 +- .../log4j2/ContextDataUtils.java | 5 +- .../OpenCensusTraceLoggingEnhancer.java | 5 +- .../OpenCensusSleuthSpanContextHolder.java | 8 +- 14 files changed, 279 insertions(+), 30 deletions(-) create mode 100644 api/src/main/java/io/opencensus/trace/ContextHandle.java create mode 100644 api/src/main/java/io/opencensus/trace/ContextManager.java create mode 100644 api/src/main/java/io/opencensus/trace/unsafe/ContextHandleImpl.java create mode 100644 api/src/main/java/io/opencensus/trace/unsafe/ContextHandleUtils.java create mode 100644 api/src/main/java/io/opencensus/trace/unsafe/ContextManagerImpl.java diff --git a/api/src/main/java/io/opencensus/trace/ContextHandle.java b/api/src/main/java/io/opencensus/trace/ContextHandle.java new file mode 100644 index 0000000000..985d261310 --- /dev/null +++ b/api/src/main/java/io/opencensus/trace/ContextHandle.java @@ -0,0 +1,24 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opencensus.trace; + +public interface ContextHandle { + + ContextHandle attach(); + + void detach(ContextHandle contextHandle); +} diff --git a/api/src/main/java/io/opencensus/trace/ContextManager.java b/api/src/main/java/io/opencensus/trace/ContextManager.java new file mode 100644 index 0000000000..c13ecc012e --- /dev/null +++ b/api/src/main/java/io/opencensus/trace/ContextManager.java @@ -0,0 +1,26 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opencensus.trace; + +public interface ContextManager { + + ContextHandle currentContext(); + + ContextHandle withValue(ContextHandle contextHandle, @javax.annotation.Nullable Span span); + + Span getValue(ContextHandle contextHandle); +} diff --git a/api/src/main/java/io/opencensus/trace/CurrentSpanUtils.java b/api/src/main/java/io/opencensus/trace/CurrentSpanUtils.java index 19d6ac9978..c09c975ea5 100644 --- a/api/src/main/java/io/opencensus/trace/CurrentSpanUtils.java +++ b/api/src/main/java/io/opencensus/trace/CurrentSpanUtils.java @@ -16,14 +16,14 @@ package io.opencensus.trace; -import io.grpc.Context; import io.opencensus.common.Scope; -import io.opencensus.trace.unsafe.ContextUtils; +import io.opencensus.trace.unsafe.ContextHandleUtils; import java.util.concurrent.Callable; import javax.annotation.Nullable; /** Util methods/functionality to interact with the {@link Span} in the {@link io.grpc.Context}. */ final class CurrentSpanUtils { + // No instance of this class. private CurrentSpanUtils() {} @@ -34,7 +34,7 @@ private CurrentSpanUtils() {} */ @Nullable static Span getCurrentSpan() { - return ContextUtils.getValue(Context.current()); + return ContextHandleUtils.getValue(ContextHandleUtils.currentContext()); } /** @@ -78,7 +78,8 @@ static Callable withSpan(Span span, boolean endSpan, Callable callable // Defines an arbitrary scope of code as a traceable operation. Supports try-with-resources idiom. private static final class ScopeInSpan implements Scope { - private final Context origContext; + + private final ContextHandle origContext; private final Span span; private final boolean endSpan; @@ -90,12 +91,13 @@ private static final class ScopeInSpan implements Scope { private ScopeInSpan(Span span, boolean endSpan) { this.span = span; this.endSpan = endSpan; - origContext = ContextUtils.withValue(Context.current(), span).attach(); + origContext = + ContextHandleUtils.withValue(ContextHandleUtils.currentContext(), span).attach(); } @Override public void close() { - Context.current().detach(origContext); + ContextHandleUtils.currentContext().detach(origContext); if (endSpan) { span.end(); } @@ -103,6 +105,7 @@ public void close() { } private static final class RunnableInSpan implements Runnable { + // TODO(bdrutu): Investigate if the extra private visibility increases the generated bytecode. private final Span span; private final Runnable runnable; @@ -116,7 +119,8 @@ private RunnableInSpan(Span span, Runnable runnable, boolean endSpan) { @Override public void run() { - Context origContext = ContextUtils.withValue(Context.current(), span).attach(); + ContextHandle origContext = + ContextHandleUtils.withValue(ContextHandleUtils.currentContext(), span).attach(); try { runnable.run(); } catch (Throwable t) { @@ -128,7 +132,7 @@ public void run() { } throw new RuntimeException("unexpected", t); } finally { - Context.current().detach(origContext); + ContextHandleUtils.currentContext().detach(origContext); if (endSpan) { span.end(); } @@ -137,6 +141,7 @@ public void run() { } private static final class CallableInSpan implements Callable { + private final Span span; private final Callable callable; private final boolean endSpan; @@ -149,7 +154,8 @@ private CallableInSpan(Span span, Callable callable, boolean endSpan) { @Override public V call() throws Exception { - Context origContext = ContextUtils.withValue(Context.current(), span).attach(); + ContextHandle origContext = + ContextHandleUtils.withValue(ContextHandleUtils.currentContext(), span).attach(); try { return callable.call(); } catch (Exception e) { @@ -162,7 +168,7 @@ public V call() throws Exception { } throw new RuntimeException("unexpected", t); } finally { - Context.current().detach(origContext); + ContextHandleUtils.currentContext().detach(origContext); if (endSpan) { span.end(); } diff --git a/api/src/main/java/io/opencensus/trace/Tracing.java b/api/src/main/java/io/opencensus/trace/Tracing.java index f55cd7754f..9de1530307 100644 --- a/api/src/main/java/io/opencensus/trace/Tracing.java +++ b/api/src/main/java/io/opencensus/trace/Tracing.java @@ -32,6 +32,7 @@ * @since 0.5 */ public final class Tracing { + private static final Logger logger = Logger.getLogger(Tracing.class.getName()); private static final TraceComponent traceComponent = loadTraceComponent(TraceComponent.class.getClassLoader()); @@ -89,6 +90,21 @@ public static TraceConfig getTraceConfig() { // Any provider that may be used for TraceComponent can be added here. @DefaultVisibilityForTesting static TraceComponent loadTraceComponent(@Nullable ClassLoader classLoader) { + try { + // Call Class.forName with literal string name of the class to help shading tools. + return Provider.createInstance( + Class.forName( + "io.opentelemetry.opencensusshim.OpenTelemetryTraceComponentImpl", + /*initialize=*/ true, + classLoader), + TraceComponent.class); + } catch (ClassNotFoundException e) { + logger.log( + Level.FINE, + "Couldn't load full implementation for OpenTelemetry TraceComponent, now trying to load " + + "original implementation.", + e); + } try { // Call Class.forName with literal string name of the class to help shading tools. return Provider.createInstance( diff --git a/api/src/main/java/io/opencensus/trace/unsafe/ContextHandleImpl.java b/api/src/main/java/io/opencensus/trace/unsafe/ContextHandleImpl.java new file mode 100644 index 0000000000..89b733dcb7 --- /dev/null +++ b/api/src/main/java/io/opencensus/trace/unsafe/ContextHandleImpl.java @@ -0,0 +1,45 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opencensus.trace.unsafe; + +import io.grpc.Context; +import io.opencensus.trace.ContextHandle; + +/** {@code ContextHandle} implementation using {@see io.grpc.Context}. */ +class ContextHandleImpl implements ContextHandle { + + private final Context context; + + public ContextHandleImpl(Context context) { + this.context = context; + } + + Context getContext() { + return context; + } + + @Override + public ContextHandle attach() { + return new ContextHandleImpl(context.attach()); + } + + @Override + public void detach(ContextHandle contextHandle) { + ContextHandleImpl impl = (ContextHandleImpl) contextHandle; + context.detach(impl.context); + } +} diff --git a/api/src/main/java/io/opencensus/trace/unsafe/ContextHandleUtils.java b/api/src/main/java/io/opencensus/trace/unsafe/ContextHandleUtils.java new file mode 100644 index 0000000000..3d14b9460a --- /dev/null +++ b/api/src/main/java/io/opencensus/trace/unsafe/ContextHandleUtils.java @@ -0,0 +1,79 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opencensus.trace.unsafe; + +import io.opencensus.internal.Provider; +import io.opencensus.trace.ContextHandle; +import io.opencensus.trace.ContextManager; +import io.opencensus.trace.Span; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +public class ContextHandleUtils { + + // No instance of this class. + private ContextHandleUtils() {} + + private static final Logger LOGGER = Logger.getLogger(ContextHandleUtils.class.getName()); + private static final ContextManager CONTEXT_MANAGER = + loadContextManager(ContextManager.class.getClassLoader()); + + private static ContextManager loadContextManager(@Nullable ClassLoader classLoader) { + try { + return Provider.createInstance( + Class.forName( + "io.opentelemetry.opencensusshim.OpenTelemetryContextManager", + /*initialize=*/ true, + classLoader), + ContextManager.class); + } catch (ClassNotFoundException e) { + LOGGER.log( + Level.FINE, + "Couldn't load full implementation for OpenTelemetry context manager, now loading " + + "original implementation.", + e); + } + return new ContextManagerImpl(); + } + + public static ContextHandle currentContext() { + return CONTEXT_MANAGER.currentContext(); + } + + /** + * Creates a new {@code ContextHandle} with the given value set. + * + * @param context the parent {@code ContextHandle}. + * @param span the value to be set. + * @return a new context with the given value set. + */ + public static ContextHandle withValue( + ContextHandle context, @javax.annotation.Nullable Span span) { + return CONTEXT_MANAGER.withValue(context, span); + } + + /** + * Returns the value from the specified {@code ContextHandle}. + * + * @param context the specified {@code ContextHandle}. + * @return the value from the specified {@code ContextHandle}. + */ + public static Span getValue(ContextHandle context) { + return CONTEXT_MANAGER.getValue(context); + } +} diff --git a/api/src/main/java/io/opencensus/trace/unsafe/ContextManagerImpl.java b/api/src/main/java/io/opencensus/trace/unsafe/ContextManagerImpl.java new file mode 100644 index 0000000000..f46d6e0e6f --- /dev/null +++ b/api/src/main/java/io/opencensus/trace/unsafe/ContextManagerImpl.java @@ -0,0 +1,52 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opencensus.trace.unsafe; + +import io.grpc.Context; +import io.opencensus.trace.ContextHandle; +import io.opencensus.trace.ContextManager; +import io.opencensus.trace.Span; +import javax.annotation.Nullable; + +/** Default {@code ContextManager} implementation using io.grpc.Context */ +public class ContextManagerImpl implements ContextManager { + + @Override + public ContextHandle currentContext() { + return wrapContext(Context.current()); + } + + @Override + public ContextHandle withValue(ContextHandle contextHandle, @Nullable Span span) { + return wrapContext(ContextUtils.withValue(unwrapContext(contextHandle), span)); + } + + @Override + public Span getValue(ContextHandle contextHandle) { + return ContextUtils.getValue(unwrapContext(contextHandle)); + } + + private static ContextHandle wrapContext(Context context) { + return new ContextHandleImpl(context); + } + + private static Context unwrapContext(ContextHandle contextHandle) { + return ((ContextHandleImpl) contextHandle).getContext(); + } + + protected ContextManagerImpl() {} +} diff --git a/api/src/main/java/io/opencensus/trace/unsafe/ContextUtils.java b/api/src/main/java/io/opencensus/trace/unsafe/ContextUtils.java index 1026512eec..46ce2856ee 100644 --- a/api/src/main/java/io/opencensus/trace/unsafe/ContextUtils.java +++ b/api/src/main/java/io/opencensus/trace/unsafe/ContextUtils.java @@ -33,7 +33,7 @@ * * @since 0.5 */ -public final class ContextUtils { +final class ContextUtils { // No instance of this class. private ContextUtils() {} diff --git a/api/src/test/java/io/opencensus/trace/CurrentSpanUtilsTest.java b/api/src/test/java/io/opencensus/trace/CurrentSpanUtilsTest.java index 4cc6fccbc1..d186197e82 100644 --- a/api/src/test/java/io/opencensus/trace/CurrentSpanUtilsTest.java +++ b/api/src/test/java/io/opencensus/trace/CurrentSpanUtilsTest.java @@ -21,9 +21,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; -import io.grpc.Context; import io.opencensus.common.Scope; -import io.opencensus.trace.unsafe.ContextUtils; +import io.opencensus.trace.unsafe.ContextHandleUtils; import java.util.concurrent.Callable; import org.junit.Before; import org.junit.Test; @@ -74,12 +73,13 @@ public void getCurrentSpan_WhenNoContext() { @Test public void getCurrentSpan() { assertThat(CurrentSpanUtils.getCurrentSpan()).isEqualTo(BlankSpan.INSTANCE); - Context origContext = ContextUtils.withValue(Context.current(), span).attach(); + ContextHandle origContext = + ContextHandleUtils.withValue(ContextHandleUtils.currentContext(), span).attach(); // Make sure context is detached even if test fails. try { assertThat(CurrentSpanUtils.getCurrentSpan()).isSameInstanceAs(span); } finally { - Context.current().detach(origContext); + ContextHandleUtils.currentContext().detach(origContext); } assertThat(CurrentSpanUtils.getCurrentSpan()).isEqualTo(BlankSpan.INSTANCE); } diff --git a/api/src/test/java/io/opencensus/trace/unsafe/ContextUtilsTest.java b/api/src/test/java/io/opencensus/trace/unsafe/ContextUtilsTest.java index 0ad9feba3d..a9da128fea 100644 --- a/api/src/test/java/io/opencensus/trace/unsafe/ContextUtilsTest.java +++ b/api/src/test/java/io/opencensus/trace/unsafe/ContextUtilsTest.java @@ -18,8 +18,8 @@ import static com.google.common.truth.Truth.assertThat; -import io.grpc.Context; import io.opencensus.trace.BlankSpan; +import io.opencensus.trace.ContextHandle; import io.opencensus.trace.Span; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,19 +31,20 @@ public class ContextUtilsTest { @Test public void testGetCurrentSpan_DefaultContext() { - Span span = ContextUtils.getValue(Context.current()); + Span span = ContextHandleUtils.getValue(ContextHandleUtils.currentContext()); assertThat(span).isEqualTo(BlankSpan.INSTANCE); } @Test public void testGetCurrentSpan_ContextSetToNull() { - Context orig = ContextUtils.withValue(Context.current(), null).attach(); + ContextHandle orig = + ContextHandleUtils.withValue(ContextHandleUtils.currentContext(), null).attach(); try { - Span span = ContextUtils.getValue(Context.current()); + Span span = ContextHandleUtils.getValue(ContextHandleUtils.currentContext()); // ContextUtils.getValue always returns non-null. assertThat(span).isEqualTo(BlankSpan.INSTANCE); } finally { - Context.current().detach(orig); + ContextHandleUtils.currentContext().detach(orig); } } } diff --git a/contrib/log_correlation/log4j2/README.md b/contrib/log_correlation/log4j2/README.md index 2827950d02..a528584b72 100644 --- a/contrib/log_correlation/log4j2/README.md +++ b/contrib/log_correlation/log4j2/README.md @@ -55,7 +55,7 @@ context: These values can be accessed from layouts with [Context Map Lookup](http://logging.apache.org/log4j/2.x/manual/lookups.html#ContextMapLookup). For -example, the trace ID can be accessed with `$${ctx:traceId}`. The values can also be accessed with +example, the trace ID can be accessed with `$${contextHandle:traceId}`. The values can also be accessed with the `X` conversion character in [`PatternLayout`](http://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout), for example, `%X{traceId}`. diff --git a/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/ContextDataUtils.java b/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/ContextDataUtils.java index d8bc5819ab..4fb052073d 100644 --- a/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/ContextDataUtils.java +++ b/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/ContextDataUtils.java @@ -16,10 +16,9 @@ package io.opencensus.contrib.logcorrelation.log4j2; -import io.grpc.Context; import io.opencensus.trace.Span; import io.opencensus.trace.SpanContext; -import io.opencensus.trace.unsafe.ContextUtils; +import io.opencensus.trace.unsafe.ContextHandleUtils; import java.util.Collection; import java.util.List; import javax.annotation.Nullable; @@ -81,7 +80,7 @@ static StringMap getContextAndTracingData() { } private static SpanContext getCurrentSpanContext() { - Span span = ContextUtils.getValue(Context.current()); + Span span = ContextHandleUtils.getValue(ContextHandleUtils.currentContext()); return span == null ? SpanContext.INVALID : span.getContext(); } } diff --git a/contrib/log_correlation/stackdriver/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancer.java b/contrib/log_correlation/stackdriver/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancer.java index bc3f2b2451..95f72d0ae3 100644 --- a/contrib/log_correlation/stackdriver/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancer.java +++ b/contrib/log_correlation/stackdriver/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancer.java @@ -19,11 +19,10 @@ import com.google.cloud.ServiceOptions; import com.google.cloud.logging.LogEntry; import com.google.cloud.logging.LoggingEnhancer; -import io.grpc.Context; import io.opencensus.trace.Span; import io.opencensus.trace.SpanContext; import io.opencensus.trace.TraceId; -import io.opencensus.trace.unsafe.ContextUtils; +import io.opencensus.trace.unsafe.ContextHandleUtils; import java.util.logging.LogManager; import javax.annotation.Nullable; @@ -99,7 +98,7 @@ public void enhanceLogEntry(LogEntry.Builder builder) { } private static SpanContext getCurrentSpanContext() { - Span span = ContextUtils.getValue(Context.current()); + Span span = ContextHandleUtils.getValue(ContextHandleUtils.currentContext()); return span == null ? SpanContext.INVALID : span.getContext(); } diff --git a/contrib/spring_sleuth_v1x/src/main/java/io/opencensus/contrib/spring/sleuth/v1x/OpenCensusSleuthSpanContextHolder.java b/contrib/spring_sleuth_v1x/src/main/java/io/opencensus/contrib/spring/sleuth/v1x/OpenCensusSleuthSpanContextHolder.java index 332058d02a..37bf2360f2 100644 --- a/contrib/spring_sleuth_v1x/src/main/java/io/opencensus/contrib/spring/sleuth/v1x/OpenCensusSleuthSpanContextHolder.java +++ b/contrib/spring_sleuth_v1x/src/main/java/io/opencensus/contrib/spring/sleuth/v1x/OpenCensusSleuthSpanContextHolder.java @@ -18,7 +18,8 @@ import io.grpc.Context; import io.opencensus.common.ExperimentalApi; -import io.opencensus.trace.unsafe.ContextUtils; +import io.opencensus.trace.ContextHandle; +import io.opencensus.trace.unsafe.ContextHandleUtils; import org.apache.commons.logging.Log; import org.springframework.cloud.sleuth.Span; import org.springframework.core.NamedThreadLocal; @@ -136,14 +137,15 @@ private static class SpanContext { final boolean autoClose; @javax.annotation.Nullable final SpanContext parent; final OpenCensusSleuthSpan ocSpan; - final Context ocCurrentContext; + final ContextHandle ocCurrentContext; private SpanContext(Span span, boolean autoClose) { this.span = span; this.autoClose = autoClose; this.parent = CURRENT_SPAN.get(); this.ocSpan = new OpenCensusSleuthSpan(span); - this.ocCurrentContext = ContextUtils.withValue(Context.current(), this.ocSpan); + this.ocCurrentContext = + ContextHandleUtils.withValue(ContextHandleUtils.currentContext(), this.ocSpan); } }