Skip to content

Commit

Permalink
Improves opencensus-shim javaagent interop
Browse files Browse the repository at this point in the history
  • Loading branch information
dmarkwat committed Nov 3, 2022
1 parent fedcbbe commit a3e2fde
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 62 deletions.
22 changes: 22 additions & 0 deletions opencensus-shim/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ plugins {
id("otel.publish-conventions")
}

val javaagent by configurations.creating

description = "OpenTelemetry OpenCensus Shim"
otelJava.moduleName.set("io.opentelemetry.opencensusshim")

Expand All @@ -21,6 +23,8 @@ dependencies {

testImplementation("io.opencensus:opencensus-impl")
testImplementation("io.opencensus:opencensus-contrib-exemplar-util")

javaagent("io.opentelemetry.javaagent:opentelemetry-javaagent:1.19.1")
}

tasks.named<Test>("test") {
Expand All @@ -29,3 +33,21 @@ tasks.named<Test>("test") {
setForkEvery(1)
maxParallelForks = 3
}

testing {
suites {
val integrationTest by registering(JvmTestSuite::class) {
dependencies {
}

targets {
all {
testTask.configure {
jvmArgs("-javaagent:${javaagent.asPath}")
environment("OTEL_TRACES_EXPORTER", "logging")
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.opencensusshim;

import io.opencensus.trace.AttributeValue;
import io.opencensus.trace.Tracing;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
import org.junit.jupiter.api.Test;

// todo remove if/once the underlying issue is agreed upon
public class ITTest {

@Test
void test() {
Tracer tracer = GlobalOpenTelemetry.get().getTracer("test");
Span span = tracer.spanBuilder("test-span").setSpanKind(SpanKind.INTERNAL).startSpan();
Scope scope = span.makeCurrent();
try {
io.opencensus.trace.Tracer ocTracer = Tracing.getTracer();
io.opencensus.trace.Span internal = ocTracer.spanBuilder("internal").startSpan();
io.opencensus.common.Scope ocScope = ocTracer.withSpan(internal);
try {
ocTracer
.getCurrentSpan()
.putAttribute("internal-only", AttributeValue.booleanAttributeValue(true));
} finally {
ocScope.close();
}
internal.end();
} finally {
scope.close();
}
span.end();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.trace;

import com.google.errorprone.annotations.MustBeClosed;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import java.time.Instant;
import java.util.concurrent.TimeUnit;

/**
* Delegates <i>all</i> {@link Span} methods to some underlying Span via {@link
* ProxyingSpan#getProxied()}.
*
* <p>If not all calls are proxied, some, such as and in particular {@link
* Span#storeInContext(Context)} and {@link Span#makeCurrent()}, will use {@code this} instead of
* the proxied {@link Span} which betrays the expectation of instance fidelity imposed by the
* underlying otel mechanisms which minted the original {@link Span}, such as the otel javaagent.
*
* <p>This proxy class simplification allows the shim to perform its duties as minimally invasively
* as possible and itself never expose its own classes and objects to callers or recipients of calls
* from the shim.
*
* <p>This addresses the inconsistency where not all methods are appropriately delegated by exposing
* a single method, {@link ProxyingSpan#getProxied()}, to simplify and better ensure delegation and
* meeting expectations.
*/
// todo make this unnecessary
@SuppressWarnings("UngroupedOverloads")
public interface ProxyingSpan extends Span {
Span getProxied();

// implementations

@Override
default <T> Span setAttribute(AttributeKey<T> key, T value) {
return getProxied().setAttribute(key, value);
}

@Override
default Span addEvent(String name, Attributes attributes) {
return getProxied().addEvent(name, attributes);
}

@Override
default Span addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit) {
return getProxied().addEvent(name, attributes, timestamp, unit);
}

@Override
default Span setStatus(StatusCode statusCode, String description) {
return getProxied().setStatus(statusCode, description);
}

@Override
default Span recordException(Throwable exception, Attributes additionalAttributes) {
return getProxied().recordException(exception, additionalAttributes);
}

@Override
default Span updateName(String name) {
return getProxied().updateName(name);
}

@Override
default void end() {
getProxied().end();
}

@Override
default void end(long timestamp, TimeUnit unit) {
getProxied().end(timestamp, unit);
}

@Override
default SpanContext getSpanContext() {
return getProxied().getSpanContext();
}

@Override
default boolean isRecording() {
return getProxied().isRecording();
}

// default overrides

@Override
default Span setAttribute(String key, String value) {
return getProxied().setAttribute(key, value);
}

@Override
default Span setAttribute(String key, long value) {
return getProxied().setAttribute(key, value);
}

@Override
default Span setAttribute(String key, double value) {
return getProxied().setAttribute(key, value);
}

@Override
default Span setAttribute(String key, boolean value) {
return getProxied().setAttribute(key, value);
}

@Override
default Span setAttribute(AttributeKey<Long> key, int value) {
return getProxied().setAttribute(key, value);
}

@Override
default Span setAllAttributes(Attributes attributes) {
return getProxied().setAllAttributes(attributes);
}

@Override
default Span addEvent(String name) {
return getProxied().addEvent(name);
}

@Override
default Span addEvent(String name, long timestamp, TimeUnit unit) {
return getProxied().addEvent(name, timestamp, unit);
}

@Override
default Span addEvent(String name, Instant timestamp) {
return getProxied().addEvent(name, timestamp);
}

@Override
default Span addEvent(String name, Attributes attributes, Instant timestamp) {
return getProxied().addEvent(name, attributes, timestamp);
}

@Override
default Span setStatus(StatusCode statusCode) {
return getProxied().setStatus(statusCode);
}

@Override
default Span recordException(Throwable exception) {
return getProxied().recordException(exception);
}

@Override
default void end(Instant timestamp) {
getProxied().end(timestamp);
}

@Override
default Context storeInContext(Context context) {
return getProxied().storeInContext(context);
}

@MustBeClosed
@Override
default Scope makeCurrent() {
return getProxied().makeCurrent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,14 @@
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.trace.ProxyingSpan;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.StatusCode;
import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.annotation.Nonnull;

class OpenTelemetrySpanImpl extends Span implements io.opentelemetry.api.trace.Span {
class OpenTelemetrySpanImpl extends Span implements io.opentelemetry.api.trace.Span, ProxyingSpan {
private static final Logger LOGGER = Logger.getLogger(OpenTelemetrySpanImpl.class.getName());
private static final EnumSet<Span.Options> RECORD_EVENTS_SPAN_OPTIONS =
EnumSet.of(Span.Options.RECORD_EVENTS);
Expand All @@ -62,15 +61,24 @@ class OpenTelemetrySpanImpl extends Span implements io.opentelemetry.api.trace.S
this.otelSpan = otelSpan;
}

// otel

@Override
public io.opentelemetry.api.trace.Span getProxied() {
return otelSpan;
}

// opencensus

@Override
public void putAttribute(String key, AttributeValue value) {
Preconditions.checkNotNull(key, "key");
Preconditions.checkNotNull(value, "value");
value.match(
arg -> otelSpan.setAttribute(key, arg),
arg -> otelSpan.setAttribute(key, arg),
arg -> otelSpan.setAttribute(key, arg),
arg -> otelSpan.setAttribute(key, arg),
arg -> ProxyingSpan.super.setAttribute(key, arg),
arg -> ProxyingSpan.super.setAttribute(key, arg),
arg -> ProxyingSpan.super.setAttribute(key, arg),
arg -> ProxyingSpan.super.setAttribute(key, arg),
arg -> null);
}

Expand All @@ -84,14 +92,14 @@ public void putAttributes(Map<String, AttributeValue> attributes) {
public void addAnnotation(String description, Map<String, AttributeValue> attributes) {
AttributesBuilder attributesBuilder = Attributes.builder();
mapAttributes(attributes, attributesBuilder);
otelSpan.addEvent(description, attributesBuilder.build());
ProxyingSpan.super.addEvent(description, attributesBuilder.build());
}

@Override
public void addAnnotation(Annotation annotation) {
AttributesBuilder attributesBuilder = Attributes.builder();
mapAttributes(annotation.getAttributes(), attributesBuilder);
otelSpan.addEvent(annotation.getDescription(), attributesBuilder.build());
ProxyingSpan.super.addEvent(annotation.getDescription(), attributesBuilder.build());
}

@Override
Expand All @@ -101,7 +109,7 @@ public void addLink(Link link) {

@Override
public void addMessageEvent(MessageEvent messageEvent) {
otelSpan.addEvent(
ProxyingSpan.super.addEvent(
String.valueOf(messageEvent.getMessageId()),
Attributes.of(
AttributeKey.stringKey(MESSAGE_EVENT_ATTRIBUTE_KEY_TYPE),
Expand All @@ -115,70 +123,22 @@ public void addMessageEvent(MessageEvent messageEvent) {
@Override
public void setStatus(Status status) {
Preconditions.checkNotNull(status, "status");
otelSpan.setStatus(status.isOk() ? StatusCode.OK : StatusCode.ERROR);
ProxyingSpan.super.setStatus(status.isOk() ? StatusCode.OK : StatusCode.ERROR);
}

@Override
public io.opentelemetry.api.trace.Span setStatus(StatusCode canonicalCode, String description) {
return otelSpan.setStatus(canonicalCode, description);
return ProxyingSpan.super.setStatus(canonicalCode, description);
}

@Override
public void end(EndSpanOptions options) {
otelSpan.end();
}

@Override
@SuppressWarnings("ParameterPackage")
public void end(long timestamp, TimeUnit unit) {
otelSpan.end(timestamp, unit);
}

@Override
public <T> io.opentelemetry.api.trace.Span setAttribute(AttributeKey<T> key, @Nonnull T value) {
return otelSpan.setAttribute(key, value);
}

@Override
public io.opentelemetry.api.trace.Span addEvent(String name) {
return otelSpan.addEvent(name);
}

@Override
public io.opentelemetry.api.trace.Span addEvent(String name, long timestamp, TimeUnit unit) {
return otelSpan.addEvent(name, timestamp, unit);
}

@Override
public io.opentelemetry.api.trace.Span addEvent(String name, Attributes attributes) {
return otelSpan.addEvent(name, attributes);
}

@Override
public io.opentelemetry.api.trace.Span addEvent(
String name, Attributes attributes, long timestamp, TimeUnit unit) {
return otelSpan.addEvent(name, attributes, timestamp, unit);
}

@Override
public io.opentelemetry.api.trace.Span recordException(Throwable exception) {
return otelSpan.recordException(exception);
}

@Override
public io.opentelemetry.api.trace.Span recordException(
Throwable exception, Attributes additionalAttributes) {
return otelSpan.recordException(exception, additionalAttributes);
}

@Override
public io.opentelemetry.api.trace.Span updateName(String name) {
return otelSpan.updateName(name);
ProxyingSpan.super.end();
}

@Override
public SpanContext getSpanContext() {
return otelSpan.getSpanContext();
return ProxyingSpan.super.getSpanContext();
}

@Override
Expand Down

0 comments on commit a3e2fde

Please sign in to comment.