Obfuscate the GlobalOpenTelemetry instance. (#2829)

* Obfuscate the GlobalOpenTelemetry instance.
This is to prevent people from casting to the SDK implementation.
Resolves #2788

* Add some more tests for the global obfuscation
This commit is contained in:
John Watson 2021-02-17 15:59:56 -08:00 committed by GitHub
parent 7c038e00e9
commit bd6a329211
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 7 deletions

View File

@ -14,6 +14,7 @@ import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/**
* A global singleton for the entrypoint to telemetry functionality for tracing, metrics and
@ -33,7 +34,7 @@ public final class GlobalOpenTelemetry {
private static final Object mutex = new Object();
@Nullable private static volatile OpenTelemetry globalOpenTelemetry;
@Nullable private static volatile ObfuscatedOpenTelemetry globalOpenTelemetry;
@GuardedBy("mutex")
@Nullable
@ -86,7 +87,7 @@ public final class GlobalOpenTelemetry {
+ "instead. Previous invocation set to cause of this exception.",
setGlobalCaller);
}
globalOpenTelemetry = openTelemetry;
globalOpenTelemetry = new ObfuscatedOpenTelemetry(openTelemetry);
setGlobalCaller = new Throwable();
}
}
@ -166,4 +167,29 @@ public final class GlobalOpenTelemetry {
return null;
}
}
/**
* Static global instances are obfuscated when they are returned from the API to prevent users
* from casting them to their SDK-specific implementation. For example, we do not want users to
* use patterns like {@code (OpenTelemetrySdk) GlobalOpenTelemetry.get()}.
*/
@ThreadSafe
static class ObfuscatedOpenTelemetry implements OpenTelemetry {
private final OpenTelemetry delegate;
ObfuscatedOpenTelemetry(OpenTelemetry delegate) {
this.delegate = delegate;
}
@Override
public TracerProvider getTracerProvider() {
return delegate.getTracerProvider();
}
@Override
public ContextPropagators getPropagators() {
return delegate.getPropagators();
}
}
}

View File

@ -6,6 +6,7 @@
package io.opentelemetry.sdk;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
import static org.mockito.Mockito.mock;
@ -43,11 +44,29 @@ class OpenTelemetrySdkTest {
@Test
void testRegisterGlobal() {
OpenTelemetrySdk sdk = OpenTelemetrySdk.builder().buildAndRegisterGlobal();
assertThat(sdk).isSameAs(GlobalOpenTelemetry.get());
assertThat(GlobalOpenTelemetry.get()).isSameAs(sdk);
assertThat(((OpenTelemetrySdk) GlobalOpenTelemetry.get()).getSdkTracerProvider().get(""))
.isSameAs(GlobalOpenTelemetry.getTracerProvider().get(""));
OpenTelemetrySdk sdk =
OpenTelemetrySdk.builder().setPropagators(propagators).buildAndRegisterGlobal();
assertThat(GlobalOpenTelemetry.get()).extracting("delegate").isSameAs(sdk);
assertThat(sdk.getTracerProvider().get(""))
.isSameAs(GlobalOpenTelemetry.getTracerProvider().get(""))
.isSameAs(GlobalOpenTelemetry.get().getTracer(""));
assertThat(GlobalOpenTelemetry.getPropagators())
.isSameAs(GlobalOpenTelemetry.get().getPropagators())
.isSameAs(sdk.getPropagators())
.isSameAs(propagators);
}
@Test
void castingGlobalToSdkFails() {
OpenTelemetrySdk.builder().buildAndRegisterGlobal();
assertThatThrownBy(
() -> {
@SuppressWarnings("unused")
OpenTelemetrySdk shouldFail = (OpenTelemetrySdk) GlobalOpenTelemetry.get();
})
.isInstanceOf(ClassCastException.class);
}
@Test