diff --git a/src/main/java/com/vaadin/extension/instrumentation/AttachExistingElementRpcHandlerInstrumentation.java b/src/main/java/com/vaadin/extension/instrumentation/AttachExistingElementRpcHandlerInstrumentation.java index 02763a2c..312331cf 100644 --- a/src/main/java/com/vaadin/extension/instrumentation/AttachExistingElementRpcHandlerInstrumentation.java +++ b/src/main/java/com/vaadin/extension/instrumentation/AttachExistingElementRpcHandlerInstrumentation.java @@ -6,9 +6,10 @@ import com.vaadin.extension.ElementInstrumentationInfo; import com.vaadin.extension.InstrumentationHelper; +import com.vaadin.extension.conf.Configuration; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.internal.StateNode; import com.vaadin.flow.internal.nodefeature.AttachExistingElementFeature; -import com.vaadin.flow.server.communication.rpc.AttachExistingElementRpcHandler; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; @@ -48,12 +49,13 @@ public void transform(TypeTransformer transformer) { public static class AttachElementAdvice { @Advice.OnMethodEnter() public static void onEnter( - @Advice.This AttachExistingElementRpcHandler attachExistingElementRpcHandler, - @Advice.Origin("#m") String methodName, @Advice.Argument(0) AttachExistingElementFeature feature, @Advice.Argument(3) StateNode node, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { + if (!Configuration.isEnabled(TraceLevel.DEFAULT)) { + return; + } // Info for the element that is being attached ElementInstrumentationInfo elementInfo = new ElementInstrumentationInfo( diff --git a/src/main/java/com/vaadin/extension/instrumentation/AttachTemplateChildRpcHandlerInstrumentation.java b/src/main/java/com/vaadin/extension/instrumentation/AttachTemplateChildRpcHandlerInstrumentation.java index b966df35..a1afc724 100644 --- a/src/main/java/com/vaadin/extension/instrumentation/AttachTemplateChildRpcHandlerInstrumentation.java +++ b/src/main/java/com/vaadin/extension/instrumentation/AttachTemplateChildRpcHandlerInstrumentation.java @@ -6,6 +6,8 @@ import com.vaadin.extension.ElementInstrumentationInfo; import com.vaadin.extension.InstrumentationHelper; +import com.vaadin.extension.conf.Configuration; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.internal.StateNode; import io.opentelemetry.api.trace.Span; @@ -48,13 +50,16 @@ public static class AttachElementAdvice { public static void onEnter(@Advice.Argument(0) StateNode node, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { + if (!Configuration.isEnabled(TraceLevel.DEFAULT)) { + return; + } // Info for the element that is being attached ElementInstrumentationInfo elementInfo = new ElementInstrumentationInfo( node); span = InstrumentationHelper.startSpan( - "AttachTemplateChild: " + elementInfo.getElementLabel()); + "Attach template child: " + elementInfo.getElementLabel()); span.setAttribute("vaadin.element.tag", elementInfo.getElement().getTag()); // If possible add active view class name as an attribute to the diff --git a/src/main/java/com/vaadin/extension/instrumentation/EventRpcHandlerInstrumentation.java b/src/main/java/com/vaadin/extension/instrumentation/EventRpcHandlerInstrumentation.java index dcd57cf4..a17a6c5b 100644 --- a/src/main/java/com/vaadin/extension/instrumentation/EventRpcHandlerInstrumentation.java +++ b/src/main/java/com/vaadin/extension/instrumentation/EventRpcHandlerInstrumentation.java @@ -9,10 +9,11 @@ import com.vaadin.extension.ElementInstrumentationInfo; import com.vaadin.extension.InstrumentationHelper; +import com.vaadin.extension.conf.Configuration; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.dom.Element; import com.vaadin.flow.internal.StateNode; import com.vaadin.flow.internal.StateTree; -import com.vaadin.flow.server.communication.rpc.EventRpcHandler; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; @@ -55,22 +56,21 @@ public void transform(TypeTransformer transformer) { public static class MethodAdvice { @Advice.OnMethodEnter() - public static void onEnter(@Advice.This EventRpcHandler eventRpcHandler, - @Advice.Origin("#m") String methodName, - @Advice.Argument(0) StateNode node, + public static void onEnter(@Advice.Argument(0) StateNode node, @Advice.Argument(1) JsonObject jsonObject, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { - String spanName = eventRpcHandler.getClass().getSimpleName() + "." - + methodName; - span = InstrumentationHelper.startSpan(spanName); - - String eventType = jsonObject.getString("event"); - if (eventType != null) { + if (Configuration.isEnabled(TraceLevel.DEFAULT)) { + String eventType = jsonObject.getString("event"); ElementInstrumentationInfo elementInfo = new ElementInstrumentationInfo( node); Element element = elementInfo.getElement(); + // append event type to make span name more descriptive + String spanName = "Event: " + elementInfo.getElementLabel() + + " :: " + eventType; + span = InstrumentationHelper.startSpan(spanName); + span.setAttribute("vaadin.element.tag", element.getTag()); span.setAttribute("vaadin.event.type", eventType); @@ -90,24 +90,17 @@ public static void onEnter(@Advice.This EventRpcHandler eventRpcHandler, span.setAttribute("vaadin.view", elementInfo.getViewLabel()); } - // append event type to make span name more descriptive - span.updateName("Event: " + elementInfo.getElementLabel() - + " :: " + eventType); - // This will make for instance a click span `vaadin-button :: - // click` instead of `EventRpcHandler.handle` which leaves open - // that what was this about - - // Set the root span name to be the event - final Optional activeRouteTemplate = getActiveRouteTemplate( - ((StateTree) node.getOwner()).getUI()); - String routeName = activeRouteTemplate.orElse(""); - String eventRootSpanName = String.format("/%s : event", - routeName); - LocalRootSpan.current().updateName(eventRootSpanName); + + Context context = currentContext().with(span); + scope = context.makeCurrent(); } - Context context = currentContext().with(span); - scope = context.makeCurrent(); + // Set the root span name to be the event + final Optional activeRouteTemplate = getActiveRouteTemplate( + ((StateTree) node.getOwner()).getUI()); + String routeName = activeRouteTemplate.orElse(""); + String eventRootSpanName = String.format("/%s : event", routeName); + LocalRootSpan.current().updateName(eventRootSpanName); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) diff --git a/src/main/java/com/vaadin/extension/instrumentation/MapSyncRpcHandlerInstrumentation.java b/src/main/java/com/vaadin/extension/instrumentation/MapSyncRpcHandlerInstrumentation.java index af24baef..571c31ce 100644 --- a/src/main/java/com/vaadin/extension/instrumentation/MapSyncRpcHandlerInstrumentation.java +++ b/src/main/java/com/vaadin/extension/instrumentation/MapSyncRpcHandlerInstrumentation.java @@ -8,9 +8,10 @@ import com.vaadin.extension.ElementInstrumentationInfo; import com.vaadin.extension.InstrumentationHelper; +import com.vaadin.extension.conf.Configuration; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.dom.Element; import com.vaadin.flow.internal.StateNode; -import com.vaadin.flow.server.communication.rpc.MapSyncRpcHandler; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; @@ -51,13 +52,14 @@ public void transform(TypeTransformer transformer) { public static class MethodAdvice { @Advice.OnMethodEnter() - public static void onEnter( - @Advice.This MapSyncRpcHandler mapSyncRpcHandler, - @Advice.Origin("#m") String methodName, - @Advice.Argument(0) StateNode node, + public static void onEnter(@Advice.Argument(0) StateNode node, @Advice.Argument(1) JsonObject jsonObject, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { + if (!Configuration.isEnabled(TraceLevel.DEFAULT)) { + return; + } + final ElementInstrumentationInfo elementInfo = new ElementInstrumentationInfo( node); final Element element = elementInfo.getElement(); diff --git a/src/main/java/com/vaadin/extension/instrumentation/NavigationRpcHandlerInstrumentation.java b/src/main/java/com/vaadin/extension/instrumentation/NavigationRpcHandlerInstrumentation.java index ce91b5b4..6716582c 100644 --- a/src/main/java/com/vaadin/extension/instrumentation/NavigationRpcHandlerInstrumentation.java +++ b/src/main/java/com/vaadin/extension/instrumentation/NavigationRpcHandlerInstrumentation.java @@ -5,7 +5,8 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import com.vaadin.extension.InstrumentationHelper; -import com.vaadin.flow.server.communication.rpc.NavigationRpcHandler; +import com.vaadin.extension.conf.Configuration; +import com.vaadin.extension.conf.TraceLevel; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; @@ -46,14 +47,13 @@ public void transform(TypeTransformer transformer) { @SuppressWarnings("unused") public static class MethodAdvice { @Advice.OnMethodEnter() - public static void onEnter( - @Advice.This NavigationRpcHandler navigationRpcHandler, - @Advice.Origin("#m") String methodName, - @Advice.Local("otelSpan") Span span, + public static void onEnter(@Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { + if (!Configuration.isEnabled(TraceLevel.MAXIMUM)) { + return; + } - String spanName = navigationRpcHandler.getClass().getSimpleName() - + "." + methodName; + String spanName = "Handle navigation"; span = InstrumentationHelper.startSpan(spanName); Context context = currentContext().with(span); diff --git a/src/main/java/com/vaadin/extension/instrumentation/PublishedServerEventHandlerRpcHandlerInstrumentation.java b/src/main/java/com/vaadin/extension/instrumentation/PublishedServerEventHandlerRpcHandlerInstrumentation.java index 1f63723a..76bd4e0b 100644 --- a/src/main/java/com/vaadin/extension/instrumentation/PublishedServerEventHandlerRpcHandlerInstrumentation.java +++ b/src/main/java/com/vaadin/extension/instrumentation/PublishedServerEventHandlerRpcHandlerInstrumentation.java @@ -7,6 +7,8 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.vaadin.extension.InstrumentationHelper; +import com.vaadin.extension.conf.Configuration; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.component.Component; import com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler; @@ -70,26 +72,21 @@ public static void onEnter( @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { - String spanName = rpcHandler.getClass().getSimpleName() + "." - + methodName; - span = InstrumentationHelper.startSpan(spanName); + if (Configuration.isEnabled(TraceLevel.MAXIMUM)) { + String spanName = rpcHandler.getClass().getSimpleName() + "." + + methodName; + span = InstrumentationHelper.startSpan(spanName); - Context context = currentContext().with(span); - scope = context.makeCurrent(); + Context context = currentContext().with(span); + scope = context.makeCurrent(); + } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void onExit(@Advice.Thrown Throwable throwable, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { - if (scope != null) { - scope.close(); - } - if (span == null) { - return; - } - InstrumentationHelper.handleException(span, throwable); - span.end(); + InstrumentationHelper.endSpan(span, throwable, scope); } } @@ -104,15 +101,17 @@ public static void onEnter(@Advice.Argument(0) Component component, return; } - String spanName = String.format("Invoke server method: %s.%s", - component.getClass().getSimpleName(), method.getName()); - span = InstrumentationHelper.startSpan(spanName); - span.setAttribute("vaadin.component", - component.getClass().getName()); - span.setAttribute("vaadin.callable.method", method.toString()); + if (Configuration.isEnabled(TraceLevel.DEFAULT)) { + String spanName = String.format("Invoke server method: %s.%s", + component.getClass().getSimpleName(), method.getName()); + span = InstrumentationHelper.startSpan(spanName); + span.setAttribute("vaadin.component", + component.getClass().getName()); + span.setAttribute("vaadin.callable.method", method.toString()); - Context context = currentContext().with(span); - scope = context.makeCurrent(); + Context context = currentContext().with(span); + scope = context.makeCurrent(); + } // Set the root span name to be the event LocalRootSpan.current().updateName( diff --git a/src/main/java/com/vaadin/extension/instrumentation/ReturnChannelHandlerInstrumentation.java b/src/main/java/com/vaadin/extension/instrumentation/ReturnChannelHandlerInstrumentation.java index a7c6789a..3e7012bd 100644 --- a/src/main/java/com/vaadin/extension/instrumentation/ReturnChannelHandlerInstrumentation.java +++ b/src/main/java/com/vaadin/extension/instrumentation/ReturnChannelHandlerInstrumentation.java @@ -5,7 +5,8 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import com.vaadin.extension.InstrumentationHelper; -import com.vaadin.flow.server.communication.ReturnChannelHandler; +import com.vaadin.extension.conf.Configuration; +import com.vaadin.extension.conf.TraceLevel; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; @@ -45,13 +46,13 @@ public void transform(TypeTransformer transformer) { public static class MethodAdvice { @Advice.OnMethodEnter() - public static void onEnter( - @Advice.This ReturnChannelHandler returnChannelHandler, - @Advice.Origin("#m") String methodName, - @Advice.Local("otelSpan") Span span, + public static void onEnter(@Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { - String spanName = returnChannelHandler.getClass().getSimpleName() - + "." + methodName; + if (!Configuration.isEnabled(TraceLevel.DEFAULT)) { + return; + } + + String spanName = "Handle return channel"; span = InstrumentationHelper.startSpan(spanName); Context context = currentContext().with(span); diff --git a/src/main/java/com/vaadin/extension/instrumentation/UidlRequestHandlerInstrumentation.java b/src/main/java/com/vaadin/extension/instrumentation/UidlRequestHandlerInstrumentation.java index 17c80f68..6b723e60 100644 --- a/src/main/java/com/vaadin/extension/instrumentation/UidlRequestHandlerInstrumentation.java +++ b/src/main/java/com/vaadin/extension/instrumentation/UidlRequestHandlerInstrumentation.java @@ -45,13 +45,15 @@ public static class SynchronizedHandleRequestAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter(@Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope) { - if (Configuration.isEnabled(TraceLevel.DEFAULT)) { - final String spanName = "Handle Client Request"; - span = InstrumentationHelper.startSpan(spanName); - - Context context = currentContext().with(span); - scope = context.makeCurrent(); + if (!Configuration.isEnabled(TraceLevel.DEFAULT)) { + return; } + + final String spanName = "Handle Client Request"; + span = InstrumentationHelper.startSpan(spanName); + + Context context = currentContext().with(span); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) diff --git a/src/test/java/com/vaadin/extension/instrumentation/AbstractInstrumentationTest.java b/src/test/java/com/vaadin/extension/instrumentation/AbstractInstrumentationTest.java index f6468fc6..6f392b9c 100644 --- a/src/test/java/com/vaadin/extension/instrumentation/AbstractInstrumentationTest.java +++ b/src/test/java/com/vaadin/extension/instrumentation/AbstractInstrumentationTest.java @@ -121,6 +121,11 @@ protected Span getCapturedSpan(int index) { return OpenTelemetryTestTools.getSpanBuilderCapture().getSpan(index); } + protected Span getCapturedSpanOrNull(int index) { + return OpenTelemetryTestTools.getSpanBuilderCapture() + .getSpanOrNull(index); + } + protected int getCapturedSpanCount() { return OpenTelemetryTestTools.getSpanBuilderCapture().getSpans().size(); } diff --git a/src/test/java/com/vaadin/extension/instrumentation/AttachExistingElementRpcHandlerInstrumentationTest.java b/src/test/java/com/vaadin/extension/instrumentation/AttachExistingElementRpcHandlerInstrumentationTest.java index ee1d487d..bd1147dc 100644 --- a/src/test/java/com/vaadin/extension/instrumentation/AttachExistingElementRpcHandlerInstrumentationTest.java +++ b/src/test/java/com/vaadin/extension/instrumentation/AttachExistingElementRpcHandlerInstrumentationTest.java @@ -2,27 +2,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.dom.Element; import com.vaadin.flow.internal.nodefeature.AttachExistingElementFeature; -import com.vaadin.flow.server.communication.rpc.AttachExistingElementRpcHandler; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.sdk.trace.data.SpanData; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; class AttachExistingElementRpcHandlerInstrumentationTest extends AbstractInstrumentationTest { - private AttachExistingElementRpcHandler attachExistingElementRpcHandler; private Element attachedElement; private Element targetElement; private AttachExistingElementFeature feature; @BeforeEach public void setup() { - attachExistingElementRpcHandler = Mockito - .mock(AttachExistingElementRpcHandler.class); attachedElement = new Element("attached-element"); targetElement = new Element("target-element"); targetElement.setText("foo"); @@ -36,8 +32,7 @@ public void setup() { @Test public void attachElement_createsSpan() { AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice - .onEnter(attachExistingElementRpcHandler, "attachElement", - feature, attachedElement.getNode(), null, null); + .onEnter(feature, attachedElement.getNode(), null, null); AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice .onExit(null, getCapturedSpan(0), null); @@ -55,8 +50,7 @@ public void attachElement_createsSpan() { @Test public void attachElementWithException_setsErrorStatus() { AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice - .onEnter(attachExistingElementRpcHandler, "attachElement", - feature, attachedElement.getNode(), null, null); + .onEnter(feature, attachedElement.getNode(), null, null); Exception exception = new RuntimeException("test error"); AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice .onExit(exception, getCapturedSpan(0), null); @@ -64,4 +58,33 @@ public void attachElementWithException_setsErrorStatus() { SpanData span = getExportedSpan(0); this.assertSpanHasException(span, exception); } + + @Test + public void attachElement_respectsTraceLevel() { + configureTraceLevel(TraceLevel.MINIMUM); + AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice + .onEnter(feature, attachedElement.getNode(), null, null); + AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(0, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.DEFAULT); + resetSpans(); + AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice + .onEnter(feature, attachedElement.getNode(), null, null); + AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.MAXIMUM); + resetSpans(); + AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice + .onEnter(feature, attachedElement.getNode(), null, null); + AttachExistingElementRpcHandlerInstrumentation.AttachElementAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + } } \ No newline at end of file diff --git a/src/test/java/com/vaadin/extension/instrumentation/AttachTemplateChildRpcHandlerInstrumentationTest.java b/src/test/java/com/vaadin/extension/instrumentation/AttachTemplateChildRpcHandlerInstrumentationTest.java index 84ba2e97..826bc77c 100644 --- a/src/test/java/com/vaadin/extension/instrumentation/AttachTemplateChildRpcHandlerInstrumentationTest.java +++ b/src/test/java/com/vaadin/extension/instrumentation/AttachTemplateChildRpcHandlerInstrumentationTest.java @@ -2,26 +2,63 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.dom.Element; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.sdk.trace.data.SpanData; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class AttachTemplateChildRpcHandlerInstrumentationTest extends AbstractInstrumentationTest { + Element attachedElement = new Element("attached-element"); + + @BeforeEach + public void setup() { + attachedElement = new Element("attached-element"); + } + @Test public void attachElement_createsSpan() { - Element attachedElement = new Element("attached-element"); AttachTemplateChildRpcHandlerInstrumentation.AttachElementAdvice .onEnter(attachedElement.getNode(), null, null); AttachTemplateChildRpcHandlerInstrumentation.AttachElementAdvice .onExit(null, getCapturedSpan(0), null); SpanData span = getExportedSpan(0); - assertEquals("AttachTemplateChild: attached-element", span.getName()); + assertEquals("Attach template child: attached-element", span.getName()); assertEquals("attached-element", span.getAttributes() .get(AttributeKey.stringKey("vaadin.element.tag"))); } + + @Test + public void attachElement_respectsTraceLevel() { + configureTraceLevel(TraceLevel.MINIMUM); + AttachTemplateChildRpcHandlerInstrumentation.AttachElementAdvice + .onEnter(attachedElement.getNode(), null, null); + AttachTemplateChildRpcHandlerInstrumentation.AttachElementAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(0, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.DEFAULT); + resetSpans(); + AttachTemplateChildRpcHandlerInstrumentation.AttachElementAdvice + .onEnter(attachedElement.getNode(), null, null); + AttachTemplateChildRpcHandlerInstrumentation.AttachElementAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.MAXIMUM); + resetSpans(); + AttachTemplateChildRpcHandlerInstrumentation.AttachElementAdvice + .onEnter(attachedElement.getNode(), null, null); + AttachTemplateChildRpcHandlerInstrumentation.AttachElementAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + } } diff --git a/src/test/java/com/vaadin/extension/instrumentation/EventRpcHandlerInstrumentationTest.java b/src/test/java/com/vaadin/extension/instrumentation/EventRpcHandlerInstrumentationTest.java index af8f750b..bffbcb45 100644 --- a/src/test/java/com/vaadin/extension/instrumentation/EventRpcHandlerInstrumentationTest.java +++ b/src/test/java/com/vaadin/extension/instrumentation/EventRpcHandlerInstrumentationTest.java @@ -5,9 +5,9 @@ import elemental.json.Json; import elemental.json.JsonObject; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Tag; -import com.vaadin.flow.server.communication.rpc.EventRpcHandler; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.StatusCode; @@ -16,17 +16,14 @@ import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; class EventRpcHandlerInstrumentationTest extends AbstractInstrumentationTest { - private EventRpcHandler eventRpcHandlerMock; TestComponent component; JsonObject jsonObject; @BeforeEach public void setup() { - eventRpcHandlerMock = Mockito.mock(EventRpcHandler.class); component = new TestComponent(); getMockUI().add(component); jsonObject = Json.createObject(); @@ -37,9 +34,8 @@ public void setup() { public void handleNode_createsSpan() { component.getElement().setText("foo"); - EventRpcHandlerInstrumentation.MethodAdvice.onEnter(eventRpcHandlerMock, - "handleNode", component.getElement().getNode(), jsonObject, - null, null); + EventRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); EventRpcHandlerInstrumentation.MethodAdvice.onExit(null, getCapturedSpan(0), null); @@ -60,9 +56,8 @@ public void handleNode_componentWithId_idUsedInSpan() { component.setId("id"); component.getElement().setText("foo"); - EventRpcHandlerInstrumentation.MethodAdvice.onEnter(eventRpcHandlerMock, - "handleNode", component.getElement().getNode(), jsonObject, - null, null); + EventRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); EventRpcHandlerInstrumentation.MethodAdvice.onExit(null, getCapturedSpan(0), null); @@ -77,9 +72,8 @@ public void handleNodeWithOpenedChangedEvent_addsOpenedChangedState() { jsonObject.put("event", "opened-changed"); component.getElement().setProperty("opened", true); - EventRpcHandlerInstrumentation.MethodAdvice.onEnter(eventRpcHandlerMock, - "handleNode", component.getElement().getNode(), jsonObject, - null, null); + EventRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); EventRpcHandlerInstrumentation.MethodAdvice.onExit(null, getCapturedSpan(0), null); @@ -92,9 +86,8 @@ public void handleNodeWithOpenedChangedEvent_addsOpenedChangedState() { component.getElement().setProperty("opened", false); - EventRpcHandlerInstrumentation.MethodAdvice.onEnter(eventRpcHandlerMock, - "handleNode", component.getElement().getNode(), jsonObject, - null, null); + EventRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); EventRpcHandlerInstrumentation.MethodAdvice.onExit(null, getCapturedSpan(0), null); @@ -107,7 +100,7 @@ public void handleNodeWithOpenedChangedEvent_addsOpenedChangedState() { public void handleNode_updatesRootSpan() { try (var ignored = withRootContext()) { EventRpcHandlerInstrumentation.MethodAdvice.onEnter( - eventRpcHandlerMock, "handleNode", + component.getElement().getNode(), jsonObject, null, null); EventRpcHandlerInstrumentation.MethodAdvice.onExit(null, getCapturedSpan(0), null); @@ -119,9 +112,8 @@ public void handleNode_updatesRootSpan() { @Test public void handleNodeWithException_setsErrorStatus() { - EventRpcHandlerInstrumentation.MethodAdvice.onEnter(eventRpcHandlerMock, - "handleNode", component.getElement().getNode(), jsonObject, - null, null); + EventRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); Exception exception = new RuntimeException("test error"); EventRpcHandlerInstrumentation.MethodAdvice.onExit(exception, getCapturedSpan(0), null); @@ -138,6 +130,50 @@ public void handleNodeWithException_setsErrorStatus() { .get(SemanticAttributes.EXCEPTION_MESSAGE)); } + @Test + public void handleNode_respectsTraceLevel() { + configureTraceLevel(TraceLevel.MINIMUM); + try (var ignored = withRootContext()) { + EventRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); + EventRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + } + // Should not export span, apart from root span + assertEquals(1, getExportedSpanCount()); + // Should update root span + SpanData rootSpan = getExportedSpan(0); + assertEquals("/test-route : event", rootSpan.getName()); + + configureTraceLevel(TraceLevel.DEFAULT); + resetSpans(); + try (var ignored = withRootContext()) { + EventRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); + EventRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + } + // Should export span + assertEquals(2, getExportedSpanCount()); + // Should update root span + rootSpan = getExportedSpan(1); + assertEquals("/test-route : event", rootSpan.getName()); + + configureTraceLevel(TraceLevel.MAXIMUM); + resetSpans(); + try (var ignored = withRootContext()) { + EventRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); + EventRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + } + // Should export span + assertEquals(2, getExportedSpanCount()); + // Should update root span + rootSpan = getExportedSpan(1); + assertEquals("/test-route : event", rootSpan.getName()); + } + @Tag("test-component") private static class TestComponent extends Component { } diff --git a/src/test/java/com/vaadin/extension/instrumentation/MapSyncRpcHandlerInstrumentationTest.java b/src/test/java/com/vaadin/extension/instrumentation/MapSyncRpcHandlerInstrumentationTest.java index b7aba8b7..6a225d4d 100644 --- a/src/test/java/com/vaadin/extension/instrumentation/MapSyncRpcHandlerInstrumentationTest.java +++ b/src/test/java/com/vaadin/extension/instrumentation/MapSyncRpcHandlerInstrumentationTest.java @@ -5,6 +5,7 @@ import elemental.json.Json; import elemental.json.JsonObject; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Tag; import com.vaadin.flow.server.communication.rpc.MapSyncRpcHandler; @@ -35,9 +36,8 @@ public void setup() { public void handleNode_createsSpan() { component.getElement().setText("foo"); - MapSyncRpcHandlerInstrumentation.MethodAdvice.onEnter(mapSyncRpcHandler, - "handleNode", component.getElement().getNode(), jsonObject, - null, null); + MapSyncRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); MapSyncRpcHandlerInstrumentation.MethodAdvice.onExit(null, getCapturedSpan(0), null); @@ -53,9 +53,8 @@ public void handleNode_createsSpan() { @Test public void handleNodeWithException_setsErrorStatus() { - MapSyncRpcHandlerInstrumentation.MethodAdvice.onEnter(mapSyncRpcHandler, - "handleNode", component.getElement().getNode(), jsonObject, - null, null); + MapSyncRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); Exception exception = new RuntimeException("test error"); MapSyncRpcHandlerInstrumentation.MethodAdvice.onExit(exception, getCapturedSpan(0), null); @@ -79,4 +78,31 @@ public void mapChange_existingValue_spanSkipped() { @Tag("test-component") private static class TestComponent extends Component { } + + @Test + public void handleNode_respectsTraceLevels() { + configureTraceLevel(TraceLevel.MINIMUM); + MapSyncRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); + MapSyncRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(0, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.DEFAULT); + MapSyncRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); + MapSyncRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.MAXIMUM); + MapSyncRpcHandlerInstrumentation.MethodAdvice.onEnter( + component.getElement().getNode(), jsonObject, null, null); + MapSyncRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + } } \ No newline at end of file diff --git a/src/test/java/com/vaadin/extension/instrumentation/NavigationRpcHandlerInstrumentationTest.java b/src/test/java/com/vaadin/extension/instrumentation/NavigationRpcHandlerInstrumentationTest.java new file mode 100644 index 00000000..3efdc41b --- /dev/null +++ b/src/test/java/com/vaadin/extension/instrumentation/NavigationRpcHandlerInstrumentationTest.java @@ -0,0 +1,51 @@ +package com.vaadin.extension.instrumentation; + +import static org.junit.jupiter.api.Assertions.*; + +import com.vaadin.extension.conf.TraceLevel; + +import io.opentelemetry.sdk.trace.data.SpanData; +import org.junit.jupiter.api.Test; + +class NavigationRpcHandlerInstrumentationTest + extends AbstractInstrumentationTest { + + @Test + public void handle_createsSpan() { + configureTraceLevel(TraceLevel.MAXIMUM); + + NavigationRpcHandlerInstrumentation.MethodAdvice.onEnter(null, null); + NavigationRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpan(0), null); + + SpanData span = getExportedSpan(0); + assertEquals("Handle navigation", span.getName()); + } + + @Test + public void handle_respectsTraceLevel() { + configureTraceLevel(TraceLevel.MINIMUM); + NavigationRpcHandlerInstrumentation.MethodAdvice.onEnter(null, null); + NavigationRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(0, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.DEFAULT); + resetSpans(); + NavigationRpcHandlerInstrumentation.MethodAdvice.onEnter(null, null); + NavigationRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(0, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.MAXIMUM); + resetSpans(); + NavigationRpcHandlerInstrumentation.MethodAdvice.onEnter(null, null); + NavigationRpcHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + + } +} \ No newline at end of file diff --git a/src/test/java/com/vaadin/extension/instrumentation/PublishedServerEventHandlerRpcHandlerInstrumentationTest.java b/src/test/java/com/vaadin/extension/instrumentation/PublishedServerEventHandlerRpcHandlerInstrumentationTest.java index e7dc4eb5..9b4e892a 100644 --- a/src/test/java/com/vaadin/extension/instrumentation/PublishedServerEventHandlerRpcHandlerInstrumentationTest.java +++ b/src/test/java/com/vaadin/extension/instrumentation/PublishedServerEventHandlerRpcHandlerInstrumentationTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import com.vaadin.extension.conf.TraceLevel; import com.vaadin.extension.instrumentation.util.OpenTelemetryTestTools; import com.vaadin.flow.component.ClientCallable; import com.vaadin.flow.component.Component; @@ -31,6 +32,7 @@ public void setup() { @Test public void handleNode_eventHandlerStartsSpan() { + configureTraceLevel(TraceLevel.MAXIMUM); PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice .onEnter(publishedServerEventHandlerRpcHandler, "handleNode", null, null); @@ -42,6 +44,38 @@ public void handleNode_eventHandlerStartsSpan() { span.getName()); } + @Test + public void handleNode_respectsTraceLevel() { + configureTraceLevel(TraceLevel.MINIMUM); + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onEnter(publishedServerEventHandlerRpcHandler, "handleNode", + null, null); + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(0, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.DEFAULT); + resetSpans(); + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onEnter(publishedServerEventHandlerRpcHandler, "handleNode", + null, null); + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(0, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.MAXIMUM); + resetSpans(); + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onEnter(publishedServerEventHandlerRpcHandler, "handleNode", + null, null); + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + } + @Test public void invokeAdvice_connectClientIsIgnored() throws NoSuchMethodException { @@ -82,6 +116,62 @@ public void invokeAdvice_callInformationIsAddedToSpan() .get(AttributeKey.stringKey("vaadin.callable.method"))); } + @Test + public void invokeAdvice_respectsTraceLevel() throws NoSuchMethodException { + configureTraceLevel(TraceLevel.MINIMUM); + try (var ignored = withRootContext()) { + PublishedServerEventHandlerRpcHandlerInstrumentation.InvokeAdvice + .onEnter(component, + TestComponent.class.getMethod("clientEvent"), null, + null); + + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + } + + // Should not export span, apart from root span + assertEquals(1, getExportedSpanCount()); + // Should update root span + SpanData rootSpan = getExportedSpan(0); + assertEquals("/test-route : ClientCallable", rootSpan.getName()); + + configureTraceLevel(TraceLevel.DEFAULT); + resetSpans(); + try (var ignored = withRootContext()) { + PublishedServerEventHandlerRpcHandlerInstrumentation.InvokeAdvice + .onEnter(component, + TestComponent.class.getMethod("clientEvent"), null, + null); + + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + } + + // Should export span + assertEquals(2, getExportedSpanCount()); + // Should update root span + rootSpan = getExportedSpan(1); + assertEquals("/test-route : ClientCallable", rootSpan.getName()); + + configureTraceLevel(TraceLevel.MAXIMUM); + resetSpans(); + try (var ignored = withRootContext()) { + PublishedServerEventHandlerRpcHandlerInstrumentation.InvokeAdvice + .onEnter(component, + TestComponent.class.getMethod("clientEvent"), null, + null); + + PublishedServerEventHandlerRpcHandlerInstrumentation.HandleAdvice + .onExit(null, getCapturedSpanOrNull(0), null); + } + + // Should export span, apart from root span + assertEquals(2, getExportedSpanCount()); + // Should update root span + rootSpan = getExportedSpan(1); + assertEquals("/test-route : ClientCallable", rootSpan.getName()); + } + @Tag("test-component") private static class TestComponent extends Component { @ClientCallable diff --git a/src/test/java/com/vaadin/extension/instrumentation/ReturnChannelHandlerInstrumentationTest.java b/src/test/java/com/vaadin/extension/instrumentation/ReturnChannelHandlerInstrumentationTest.java index 881625be..7c432d61 100644 --- a/src/test/java/com/vaadin/extension/instrumentation/ReturnChannelHandlerInstrumentationTest.java +++ b/src/test/java/com/vaadin/extension/instrumentation/ReturnChannelHandlerInstrumentationTest.java @@ -2,38 +2,27 @@ import static org.junit.jupiter.api.Assertions.*; -import com.vaadin.flow.server.communication.ReturnChannelHandler; +import com.vaadin.extension.conf.TraceLevel; import io.opentelemetry.sdk.trace.data.SpanData; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; class ReturnChannelHandlerInstrumentationTest extends AbstractInstrumentationTest { - ReturnChannelHandler returnChannelHandler; - - @BeforeEach - public void setup() { - returnChannelHandler = Mockito.mock(ReturnChannelHandler.class); - } - @Test public void handleNode_createsSpan() { - ReturnChannelHandlerInstrumentation.MethodAdvice - .onEnter(returnChannelHandler, "handleNode", null, null); + ReturnChannelHandlerInstrumentation.MethodAdvice.onEnter(null, null); ReturnChannelHandlerInstrumentation.MethodAdvice.onExit(null, getCapturedSpan(0), null); SpanData span = getExportedSpan(0); - assertEquals("ReturnChannelHandler.handleNode", span.getName()); + assertEquals("Handle return channel", span.getName()); } @Test public void handleNodeWithException_setsErrorStatus() { - ReturnChannelHandlerInstrumentation.MethodAdvice - .onEnter(returnChannelHandler, "handleNode", null, null); + ReturnChannelHandlerInstrumentation.MethodAdvice.onEnter(null, null); Exception exception = new RuntimeException("test error"); ReturnChannelHandlerInstrumentation.MethodAdvice.onExit(exception, getCapturedSpan(0), null); @@ -41,4 +30,30 @@ public void handleNodeWithException_setsErrorStatus() { SpanData span = getExportedSpan(0); this.assertSpanHasException(span, exception); } + + @Test + public void handleNode_respectsTraceLevel() { + configureTraceLevel(TraceLevel.MINIMUM); + ReturnChannelHandlerInstrumentation.MethodAdvice.onEnter(null, null); + ReturnChannelHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(0, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.DEFAULT); + resetSpans(); + ReturnChannelHandlerInstrumentation.MethodAdvice.onEnter(null, null); + ReturnChannelHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + + configureTraceLevel(TraceLevel.MAXIMUM); + resetSpans(); + ReturnChannelHandlerInstrumentation.MethodAdvice.onEnter(null, null); + ReturnChannelHandlerInstrumentation.MethodAdvice.onExit(null, + getCapturedSpanOrNull(0), null); + + assertEquals(1, getExportedSpanCount()); + } } \ No newline at end of file diff --git a/src/test/java/com/vaadin/extension/instrumentation/util/SpanBuilderCapture.java b/src/test/java/com/vaadin/extension/instrumentation/util/SpanBuilderCapture.java index cea58979..4a3b9b74 100644 --- a/src/test/java/com/vaadin/extension/instrumentation/util/SpanBuilderCapture.java +++ b/src/test/java/com/vaadin/extension/instrumentation/util/SpanBuilderCapture.java @@ -23,6 +23,13 @@ public Span getSpan(int index) { return spans.get(index); } + public Span getSpanOrNull(int index) { + if (index < spans.size()) { + return spans.get(index); + } + return null; + } + public void reset() { spans.clear(); }