Capture gRPC messages as events instead of child spans
* Capture gRPC messages as events
* Rename verification method to avoid conflicts
It's common to have a 'name' test parameter/field which then causes
conflicts with verification method of the same name 'name'.
MODIFY
instrumentation/grpc-1.5/src/main/java/io/opentelemetry/auto/instrumentation/grpc/client/TracingClientInterceptor.java
instrumentation/grpc-1.5/src/main/java/io/opentelemetry/auto/instrumentation/grpc/client/TracingClientInterceptor.java
@@ -16,7 +16,11 @@ import io.grpc.MethodDescriptor;
import io.grpc.Status;
import io.opentelemetry.auto.instrumentation.api.MoreTags;
import io.opentelemetry.context.Scope;
+import io.opentelemetry.trace.AttributeValue;
import io.opentelemetry.trace.Span;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
public class TracingClientInterceptor implements ClientInterceptor {
@@ -84,7 +88,8 @@ public class TracingClientInterceptor implements ClientInterceptor {
static final class TracingClientCallListener<RespT>
extends ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT> {
- final Span span;
+ private final Span span;
+ private final AtomicInteger messageId = new AtomicInteger();
TracingClientCallListener(final Span span, final ClientCall.Listener<RespT> delegate) {
super(delegate);
@@ -93,18 +98,12 @@ public class TracingClientInterceptor implements ClientInterceptor {
@Override
public void onMessage(final RespT message) {
- final Span messageSpan =
- TRACER.spanBuilder("grpc.message").setSpanKind(CLIENT).setParent(span).startSpan();
- messageSpan.setAttribute("message.type", message.getClass().getName());
- DECORATE.afterStart(messageSpan);
- try (final Scope scope = TRACER.withSpan(messageSpan)) {
+ final Map<String, AttributeValue> attributes = new HashMap<>();
+ attributes.put("message.type", AttributeValue.stringAttributeValue("SENT"));
+ attributes.put("message.id", AttributeValue.longAttributeValue(messageId.incrementAndGet()));
+ span.addEvent("message", attributes);
+ try (final Scope scope = TRACER.withSpan(span)) {
delegate().onMessage(message);
- } catch (final Throwable e) {
- DECORATE.onError(messageSpan, e);
- throw e;
- } finally {
- DECORATE.beforeFinish(messageSpan);
- messageSpan.end();
}
}

MODIFY
instrumentation/grpc-1.5/src/main/java/io/opentelemetry/auto/instrumentation/grpc/server/TracingServerInterceptor.java
instrumentation/grpc-1.5/src/main/java/io/opentelemetry/auto/instrumentation/grpc/server/TracingServerInterceptor.java
@@ -14,8 +14,12 @@ import io.grpc.ServerInterceptor;
import io.grpc.Status;
import io.opentelemetry.auto.instrumentation.api.MoreTags;
import io.opentelemetry.context.Scope;
+import io.opentelemetry.trace.AttributeValue;
import io.opentelemetry.trace.Span;
import io.opentelemetry.trace.SpanContext;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
public class TracingServerInterceptor implements ServerInterceptor {
@@ -89,6 +93,7 @@ public class TracingServerInterceptor implements ServerInterceptor {
static final class TracingServerCallListener<ReqT>
extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
private final Span span;
+ private final AtomicInteger messageId = new AtomicInteger();
TracingServerCallListener(final Span span, final ServerCall.Listener<ReqT> delegate) {
super(delegate);
@@ -97,26 +102,12 @@ public class TracingServerInterceptor implements ServerInterceptor {
@Override
public void onMessage(final ReqT message) {
- final Span span =
- TRACER
- .spanBuilder("grpc.message")
- .setSpanKind(SERVER)
- .setParent(this.span.getContext())
- .startSpan();
- span.setAttribute("message.type", message.getClass().getName());
- DECORATE.afterStart(span);
- final Scope scope = TRACER.withSpan(span);
- try {
+ final Map<String, AttributeValue> attributes = new HashMap<>();
+ attributes.put("message.type", AttributeValue.stringAttributeValue("RECEIVED"));
+ attributes.put("message.id", AttributeValue.longAttributeValue(messageId.incrementAndGet()));
+ span.addEvent("message", attributes);
+ try (final Scope scope = TRACER.withSpan(span)) {
delegate().onMessage(message);
- } catch (final Throwable e) {
- DECORATE.onError(span, e);
- DECORATE.beforeFinish(this.span);
- this.span.end();
- throw e;
- } finally {
- DECORATE.beforeFinish(span);
- span.end();
- scope.close();
}
}

MODIFY
instrumentation/grpc-1.5/src/test/groovy/GrpcStreamingTest.groovy
instrumentation/grpc-1.5/src/test/groovy/GrpcStreamingTest.groovy
@@ -10,7 +10,6 @@ import io.opentelemetry.auto.instrumentation.api.MoreTags
import io.opentelemetry.auto.instrumentation.api.SpanTypes
import io.opentelemetry.auto.instrumentation.api.Tags
import io.opentelemetry.auto.test.AgentTestRunner
-import io.opentelemetry.sdk.trace.SpanData
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.TimeUnit
@@ -86,22 +85,7 @@ class GrpcStreamingTest extends AgentTestRunner {
error.get() == null
assertTraces(1) {
- trace(0, clientMessageCount * serverMessageCount + 1 + clientMessageCount + 1) {
- sortSpans {
- // sort for consistent ordering
- List<SpanData> serverMessages = new ArrayList<>()
- for (SpanData span : spans) {
- if (span.name == "grpc.message" && span.attributes[Tags.COMPONENT].stringValue == "grpc-server") {
- serverMessages.add(span)
- }
- if (span.name == "grpc.server" && span.attributes[Tags.COMPONENT].stringValue == "grpc-server") {
- serverMessages.add(0, span)
- }
- }
- // move the server messages to the end
- spans.removeAll(serverMessages)
- spans.addAll(serverMessages)
- }
+ trace(0, 2) {
span(0) {
operationName "grpc.client"
spanKind CLIENT
@@ -113,22 +97,18 @@ class GrpcStreamingTest extends AgentTestRunner {
"$Tags.COMPONENT" "grpc-client"
"status.code" "OK"
}
- }
(1..(clientMessageCount * serverMessageCount)).each {
- println it
- span(it) {
- operationName "grpc.message"
- spanKind CLIENT
- childOf span(0)
- errored false
- tags {
- "$MoreTags.SPAN_TYPE" SpanTypes.RPC
- "$Tags.COMPONENT" "grpc-client"
- "message.type" "example.Helloworld\$Response"
+ def messageId = it
+ event(it - 1) {
+ eventName "message"
+ attributes {
+ "message.type" "SENT"
+ "message.id" messageId
+ }
}
}
}
- span(clientMessageCount * serverMessageCount + 1) {
+ span(1) {
operationName "grpc.server"
spanKind SERVER
childOf span(0)
@@ -139,17 +119,14 @@ class GrpcStreamingTest extends AgentTestRunner {
"$Tags.COMPONENT" "grpc-server"
"status.code" "OK"
}
- }
clientRange.each {
- span(clientMessageCount * serverMessageCount + 1 + it) {
- operationName "grpc.message"
- spanKind SERVER
- childOf span(clientMessageCount * serverMessageCount + 1)
- errored false
- tags {
- "$MoreTags.SPAN_TYPE" SpanTypes.RPC
- "$Tags.COMPONENT" "grpc-server"
- "message.type" "example.Helloworld\$Response"
+ def messageId = it
+ event(it - 1) {
+ eventName "message"
+ attributes {
+ "message.type" "RECEIVED"
+ "message.id" messageId
+ }
}
}
}

MODIFY
instrumentation/grpc-1.5/src/test/groovy/GrpcTest.groovy
instrumentation/grpc-1.5/src/test/groovy/GrpcTest.groovy
@@ -12,7 +12,6 @@ import io.opentelemetry.auto.instrumentation.api.MoreTags
import io.opentelemetry.auto.instrumentation.api.SpanTypes
import io.opentelemetry.auto.instrumentation.api.Tags
import io.opentelemetry.auto.test.AgentTestRunner
-import io.opentelemetry.sdk.trace.SpanData
import java.util.concurrent.TimeUnit
@@ -44,27 +43,19 @@ class GrpcTest extends AgentTestRunner {
response.message == "Hello $name"
assertTraces(1) {
- trace(0, 4) {
- sortSpans {
- // sort for consistent ordering
- List<SpanData> serverMessages = new ArrayList<>()
- for (SpanData span : spans) {
- if (span.name == "grpc.message" && span.attributes[Tags.COMPONENT].stringValue == "grpc-server") {
- serverMessages.add(span)
- }
- if (span.name == "grpc.server" && span.attributes[Tags.COMPONENT].stringValue == "grpc-server") {
- serverMessages.add(0, span)
- }
- }
- // move the server messages to the end
- spans.removeAll(serverMessages)
- spans.addAll(serverMessages)
- }
+ trace(0, 2) {
span(0) {
operationName "grpc.client"
spanKind CLIENT
parent()
errored false
+ event(0) {
+ eventName "message"
+ attributes {
+ "message.type" "SENT"
+ "message.id" 1
+ }
+ }
tags {
"$MoreTags.RESOURCE_NAME" "example.Greeter/SayHello"
"$MoreTags.SPAN_TYPE" SpanTypes.RPC
@@ -73,37 +64,22 @@ class GrpcTest extends AgentTestRunner {
}
}
span(1) {
- operationName "grpc.message"
- spanKind CLIENT
- childOf span(0)
- errored false
- tags {
- "$MoreTags.SPAN_TYPE" SpanTypes.RPC
- "$Tags.COMPONENT" "grpc-client"
- "message.type" "example.Helloworld\$Response"
- }
- }
- span(2) {
operationName "grpc.server"
spanKind SERVER
childOf span(0)
errored false
- tags {
- "$MoreTags.RESOURCE_NAME" "example.Greeter/SayHello"
- "$MoreTags.SPAN_TYPE" SpanTypes.RPC
- "$Tags.COMPONENT" "grpc-server"
- "status.code" "OK"
+ event(0) {
+ eventName "message"
+ attributes {
+ "message.type" "RECEIVED"
+ "message.id" 1
}
}
- span(3) {
- operationName "grpc.message"
- spanKind SERVER
- childOf span(2)
- errored false
tags {
+ "$MoreTags.RESOURCE_NAME" "example.Greeter/SayHello"
"$MoreTags.SPAN_TYPE" SpanTypes.RPC
"$Tags.COMPONENT" "grpc-server"
- "message.type" "example.Helloworld\$Request"
+ "status.code" "OK"
}
}
}
@@ -139,7 +115,7 @@ class GrpcTest extends AgentTestRunner {
thrown StatusRuntimeException
assertTraces(1) {
- trace(0, 3) {
+ trace(0, 2) {
span(0) {
operationName "grpc.client"
spanKind CLIENT
@@ -158,6 +134,13 @@ class GrpcTest extends AgentTestRunner {
spanKind SERVER
childOf span(0)
errored true
+ event(0) {
+ eventName "message"
+ attributes {
+ "message.type" "RECEIVED"
+ "message.id" 1
+ }
+ }
tags {
"$MoreTags.RESOURCE_NAME" "example.Greeter/SayHello"
"$MoreTags.SPAN_TYPE" SpanTypes.RPC
@@ -169,17 +152,6 @@ class GrpcTest extends AgentTestRunner {
}
}
}
- span(2) {
- operationName "grpc.message"
- spanKind SERVER
- childOf span(1)
- errored false
- tags {
- "$MoreTags.SPAN_TYPE" SpanTypes.RPC
- "$Tags.COMPONENT" "grpc-server"
- "message.type" "example.Helloworld\$Request"
- }
- }
}
}
@@ -219,7 +191,7 @@ class GrpcTest extends AgentTestRunner {
thrown StatusRuntimeException
assertTraces(1) {
- trace(0, 3) {
+ trace(0, 2) {
span(0) {
operationName "grpc.client"
spanKind CLIENT
@@ -237,22 +209,18 @@ class GrpcTest extends AgentTestRunner {
spanKind SERVER
childOf span(0)
errored true
- tags {
- "$MoreTags.RESOURCE_NAME" "example.Greeter/SayHello"
- "$MoreTags.SPAN_TYPE" SpanTypes.RPC
- "$Tags.COMPONENT" "grpc-server"
- errorTags error.class, error.message
+ event(0) {
+ eventName "message"
+ attributes {
+ "message.type" "RECEIVED"
+ "message.id" 1
}
}
- span(2) {
- operationName "grpc.message"
- spanKind SERVER
- childOf span(1)
- errored false
tags {
+ "$MoreTags.RESOURCE_NAME" "example.Greeter/SayHello"
"$MoreTags.SPAN_TYPE" SpanTypes.RPC
"$Tags.COMPONENT" "grpc-server"
- "message.type" "example.Helloworld\$Request"
+ errorTags error.class, error.message
}
}
}

MODIFY
testing/src/main/groovy/io/opentelemetry/auto/test/asserts/EventAssert.groovy
testing/src/main/groovy/io/opentelemetry/auto/test/asserts/EventAssert.groovy
@@ -30,7 +30,7 @@ class EventAssert {
clone(this)
}
- def name(String name) {
+ def eventName(String name) {
assert event.name == name
checked.name = true
}

MODIFY
testing/src/main/groovy/io/opentelemetry/auto/test/log/events/LogEventsTestBase.groovy
testing/src/main/groovy/io/opentelemetry/auto/test/log/events/LogEventsTestBase.groovy
@@ -47,7 +47,7 @@ abstract class LogEventsTestBase extends AgentTestRunner {
operationName "test"
if (capture) {
event(0) {
- name "xyz"
+ eventName "xyz"
attributes {
"level" testMethod.toUpperCase()
"loggerName" "abc"

Capture gRPC messages as events instead of child spans (#185)

* Capture gRPC messages as events

* Rename verification method to avoid conflicts

It's common to have a 'name' test parameter/field which then causes
conflicts with verification method of the same name 'name'.