From b04a39db1d000b2702d88a81f443368f3ace664b Mon Sep 17 00:00:00 2001 From: sravani-revuri Date: Thu, 9 Jul 2026 10:05:56 +0530 Subject: [PATCH 1/5] HDDS-15781. Adding Spankind information to ozone sh commands --- hadoop-hdds/client/pom.xml | 4 ++ .../hadoop/hdds/scm/XceiverClientGrpc.java | 5 +- .../hadoop/hdds/scm/XceiverClientRatis.java | 3 +- .../hdds/tracing/GrpcServerInterceptor.java | 4 +- .../hadoop/hdds/tracing/TraceAllMethod.java | 8 ++- .../hadoop/hdds/tracing/TracingUtil.java | 52 +++++++++++++++---- .../transport/server/XceiverServerGrpc.java | 4 +- .../server/ratis/XceiverServerRatis.java | 4 +- .../OzoneProtocolMessageDispatcher.java | 3 +- hadoop-ozone/cli-shell/pom.xml | 4 ++ .../org/apache/hadoop/ozone/shell/Shell.java | 3 +- 11 files changed, 75 insertions(+), 19 deletions(-) diff --git a/hadoop-hdds/client/pom.xml b/hadoop-hdds/client/pom.xml index 729fa39b96e1..256f4622006b 100644 --- a/hadoop-hdds/client/pom.xml +++ b/hadoop-hdds/client/pom.xml @@ -32,6 +32,10 @@ com.google.guava guava + + io.opentelemetry + opentelemetry-api + jakarta.annotation jakarta.annotation-api diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientGrpc.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientGrpc.java index 90e581e8f4be..46ead567f1ea 100644 --- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientGrpc.java +++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientGrpc.java @@ -20,6 +20,7 @@ import static org.apache.hadoop.hdds.HddsUtils.processForDebug; import com.google.common.annotations.VisibleForTesting; +import io.opentelemetry.api.trace.SpanKind; import java.io.IOException; import java.io.InterruptedIOException; import java.io.UncheckedIOException; @@ -421,7 +422,7 @@ private XceiverClientReply sendCommandWithTraceIDAndRetry( String spanName = "XceiverClientGrpc." + request.getCmdType().name(); - return TracingUtil.executeInNewSpan(spanName, + return TracingUtil.executeInNewSpan(spanName, SpanKind.CLIENT, () -> { ContainerCommandRequestProto.Builder builder = ContainerCommandRequestProto.newBuilder(request) @@ -676,7 +677,7 @@ public XceiverClientReply sendCommandAsync( throws IOException, ExecutionException, InterruptedException { try (TracingUtil.TraceCloseable ignored = TracingUtil.createActivatedSpan( - "XceiverClientGrpc." + request.getCmdType().name())) { + "XceiverClientGrpc." + request.getCmdType().name(), SpanKind.CLIENT)) { ContainerCommandRequestProto.Builder builder = ContainerCommandRequestProto.newBuilder(request) diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientRatis.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientRatis.java index 08ad7298e2a2..e24e326920c8 100644 --- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientRatis.java +++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientRatis.java @@ -19,6 +19,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import io.opentelemetry.api.trace.SpanKind; import java.io.IOException; import java.util.Collection; import java.util.Comparator; @@ -253,7 +254,7 @@ private CompletableFuture sendRequestAsync( } } return TracingUtil.executeInNewSpan( - "XceiverClientRatis." + request.getCmdType().name(), + "XceiverClientRatis." + request.getCmdType().name(), SpanKind.CLIENT, () -> { final ContainerCommandRequestMessage message = ContainerCommandRequestMessage.toMessage( diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/GrpcServerInterceptor.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/GrpcServerInterceptor.java index af1b77facd18..5deea9f8b0c3 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/GrpcServerInterceptor.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/GrpcServerInterceptor.java @@ -18,6 +18,7 @@ package org.apache.hadoop.hdds.tracing; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.context.Scope; import org.apache.ratis.thirdparty.io.grpc.ForwardingServerCallListener.SimpleForwardingServerCallListener; import org.apache.ratis.thirdparty.io.grpc.Metadata; @@ -44,7 +45,8 @@ public void onMessage(ReqT message) { Span span = TracingUtil .importAndCreateSpan( call.getMethodDescriptor().getFullMethodName(), - headers.get(GrpcClientInterceptor.TRACING_HEADER)); + headers.get(GrpcClientInterceptor.TRACING_HEADER), + SpanKind.SERVER); try (Scope ignored = span.makeCurrent()) { super.onMessage(message); } finally { diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java index 623e004a96ed..1e5ab249bb25 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java @@ -19,6 +19,7 @@ import static java.util.Collections.emptyMap; +import io.opentelemetry.api.trace.SpanKind; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Arrays; @@ -77,7 +78,12 @@ public Object invoke(Object proxy, Method method, Object[] args) } } - try (TracingUtil.TraceCloseable ignored = TracingUtil.createActivatedSpan(name + "." + method.getName())) { + SpanKind spanKind = "close".equals(method.getName()) + ? SpanKind.INTERNAL + : SpanKind.CLIENT; + + try (TracingUtil.TraceCloseable ignored = TracingUtil.createActivatedSpan( + name + "." + method.getName(), spanKind)) { try { return delegateMethod.invoke(delegate, args); } catch (Exception ex) { diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java index d25817a7a7d0..1a7e4d278d15 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java @@ -21,6 +21,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; @@ -121,9 +122,18 @@ public static R execute( String spanName, ConfigurationSource conf, CheckedSupplier supplier) throws E { + return execute(serviceName, spanName, SpanKind.INTERNAL, conf, supplier); + } + + public static R execute( + String serviceName, + String spanName, + SpanKind spanKind, + ConfigurationSource conf, + CheckedSupplier supplier) throws E { initTracing(serviceName, conf); try { - return executeInNewSpan(spanName, supplier); + return executeInNewSpan(spanName, spanKind, supplier); } finally { flushTracing(); } @@ -217,15 +227,18 @@ public static String exportCurrentSpan() { * @return Tracing scope. */ public static Span importAndCreateSpan(String name, String encodedParent) { + return importAndCreateSpan(name, encodedParent, SpanKind.INTERNAL); + } + + public static Span importAndCreateSpan(String name, String encodedParent, + SpanKind spanKind) { if (encodedParent == null || encodedParent.isEmpty()) { - return tracer.spanBuilder(name).setNoParent().startSpan(); + return tracer.spanBuilder(name).setNoParent().setSpanKind(spanKind).startSpan(); } W3CTraceContextPropagator propagator = W3CTraceContextPropagator.getInstance(); Context extract = propagator.extract(Context.current(), encodedParent, new TextExtractor()); - return tracer.spanBuilder(name) - .setParent(extract) - .startSpan(); + return tracer.spanBuilder(name).setParent(extract).setSpanKind(spanKind).startSpan(); } /** @@ -298,7 +311,12 @@ static Map parseSpanSamplingConfig(String configStr) { */ public static void executeInNewSpan(String spanName, CheckedRunnable runnable) throws E { - Span span = buildSpan(spanName); + executeInNewSpan(spanName, SpanKind.INTERNAL, runnable); + } + + public static void executeInNewSpan(String spanName, + SpanKind spanKind, CheckedRunnable runnable) throws E { + Span span = buildSpan(spanName, spanKind); executeInSpan(span, runnable); } @@ -307,7 +325,12 @@ public static void executeInNewSpan(String spanName, */ public static R executeInNewSpan(String spanName, CheckedSupplier supplier) throws E { - Span span = buildSpan(spanName); + return executeInNewSpan(spanName, SpanKind.INTERNAL, supplier); + } + + public static R executeInNewSpan(String spanName, + SpanKind spanKind, CheckedSupplier supplier) throws E { + Span span = buildSpan(spanName, spanKind); return executeInSpan(span, supplier); } @@ -361,7 +384,11 @@ public static void executeAsChildSpan(String spanName, * in case of Exceptions. */ public static TraceCloseable createActivatedSpan(String spanName) { - Span span = buildSpan(spanName); + return createActivatedSpan(spanName, SpanKind.INTERNAL); + } + + public static TraceCloseable createActivatedSpan(String spanName, SpanKind spanKind) { + Span span = buildSpan(spanName, spanKind); Scope scope = span.makeCurrent(); return () -> { scope.close(); @@ -422,13 +449,17 @@ private void parse(String carrier) { * otherwise, creates a root span. */ private static Span buildSpan(String spanName) { + return buildSpan(spanName, SpanKind.INTERNAL); + } + + private static Span buildSpan(String spanName, SpanKind spanKind) { Context currentContext = Context.current(); Span parentSpan = Span.fromContext(currentContext); if (parentSpan.getSpanContext().isValid()) { - return tracer.spanBuilder(spanName).setParent(currentContext).startSpan(); + return tracer.spanBuilder(spanName).setParent(currentContext).setSpanKind(spanKind).startSpan(); } else { - return tracer.spanBuilder(spanName).setNoParent().startSpan(); + return tracer.spanBuilder(spanName).setNoParent().setSpanKind(spanKind).startSpan(); } } @@ -464,6 +495,7 @@ public static TraceCloseable createActivatedSpanFromW3cHttpHeaders( Span span = tracer.spanBuilder(spanName) .setParent(remote) + .setSpanKind(SpanKind.SERVER) .startSpan(); Scope scope = span.makeCurrent(); diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/XceiverServerGrpc.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/XceiverServerGrpc.java index 0afbabb96a23..1cc7607d2a2a 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/XceiverServerGrpc.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/XceiverServerGrpc.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.context.Scope; import java.io.IOException; import java.net.BindException; @@ -240,7 +241,8 @@ public void submitRequest(ContainerCommandRequestProto request, Span span = TracingUtil .importAndCreateSpan( "XceiverServerGrpc." + request.getCmdType().name(), - request.getTraceID()); + request.getTraceID(), + SpanKind.SERVER); try (Scope ignore = span.makeCurrent()) { ContainerProtos.ContainerCommandResponseProto response = storageContainer.dispatch(request, null); diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/ratis/XceiverServerRatis.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/ratis/XceiverServerRatis.java index 6eadec2d6d36..b4a2ae8f0003 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/ratis/XceiverServerRatis.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/ratis/XceiverServerRatis.java @@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.context.Scope; import java.io.File; import java.io.IOException; @@ -658,7 +659,8 @@ public void submitRequest(ContainerCommandRequestProto request, Span span = TracingUtil .importAndCreateSpan( "XceiverServerRatis." + request.getCmdType().name(), - request.getTraceID()); + request.getTraceID(), + SpanKind.SERVER); try (Scope ignored = span.makeCurrent()) { RaftClientRequest raftClientRequest = createRaftClientRequest(request, pipelineID, diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/OzoneProtocolMessageDispatcher.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/OzoneProtocolMessageDispatcher.java index 94a35d488abb..29fc54642eb7 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/OzoneProtocolMessageDispatcher.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/OzoneProtocolMessageDispatcher.java @@ -19,6 +19,7 @@ import com.google.protobuf.ServiceException; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.context.Scope; import java.util.function.Function; import org.apache.hadoop.hdds.tracing.TracingUtil; @@ -71,7 +72,7 @@ public RESPONSE processRequest( CheckedFunction methodCall, TYPE type, String traceId) throws ServiceException { - Span span = TracingUtil.importAndCreateSpan(type.toString(), traceId); + Span span = TracingUtil.importAndCreateSpan(type.toString(), traceId, SpanKind.SERVER); try (Scope currentScope = span.makeCurrent()) { if (logger.isTraceEnabled()) { logger.trace( diff --git a/hadoop-ozone/cli-shell/pom.xml b/hadoop-ozone/cli-shell/pom.xml index 015ad13b59b0..dd1043661f9d 100644 --- a/hadoop-ozone/cli-shell/pom.xml +++ b/hadoop-ozone/cli-shell/pom.xml @@ -55,6 +55,10 @@ info.picocli picocli-shell-jline3 + + io.opentelemetry + opentelemetry-api + jakarta.xml.bind jakarta.xml.bind-api diff --git a/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/Shell.java b/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/Shell.java index f3e5efdd98a1..0ae6c5b850fe 100644 --- a/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/Shell.java +++ b/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/Shell.java @@ -17,6 +17,7 @@ package org.apache.hadoop.ozone.shell; +import io.opentelemetry.api.trace.SpanKind; import java.util.Collections; import java.util.List; import org.apache.hadoop.hdds.cli.GenericCli; @@ -100,7 +101,7 @@ private int execute(CommandLine.ParseResult parseResult) { } String spanName = spec.name() + " " + String.join(" ", parseResult.originalArgs()); - return TracingUtil.execute("shell", spanName, getOzoneConf(), + return TracingUtil.execute("shell", spanName, SpanKind.INTERNAL, getOzoneConf(), () -> new CommandLine.RunLast().execute(parseResult)); } From fd8bf753e35a22b80da3df2199eefeee4c365eaa Mon Sep 17 00:00:00 2001 From: sravani-revuri Date: Thu, 9 Jul 2026 10:20:23 +0530 Subject: [PATCH 2/5] pmd --- .../java/org/apache/hadoop/hdds/tracing/TracingUtil.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java index 1a7e4d278d15..938ff1edb017 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java @@ -238,7 +238,10 @@ public static Span importAndCreateSpan(String name, String encodedParent, W3CTraceContextPropagator propagator = W3CTraceContextPropagator.getInstance(); Context extract = propagator.extract(Context.current(), encodedParent, new TextExtractor()); - return tracer.spanBuilder(name).setParent(extract).setSpanKind(spanKind).startSpan(); + return tracer.spanBuilder(name). + setParent(extract). + setSpanKind(spanKind). + startSpan(); } /** @@ -448,10 +451,6 @@ private void parse(String carrier) { * Creates a new span, using the current context as a parent if valid; * otherwise, creates a root span. */ - private static Span buildSpan(String spanName) { - return buildSpan(spanName, SpanKind.INTERNAL); - } - private static Span buildSpan(String spanName, SpanKind spanKind) { Context currentContext = Context.current(); Span parentSpan = Span.fromContext(currentContext); From f63bfe36944442ca5ca87a2ceb125ebbd870a88f Mon Sep 17 00:00:00 2001 From: sravani-revuri Date: Thu, 9 Jul 2026 10:24:37 +0530 Subject: [PATCH 3/5] visual change --- .../java/org/apache/hadoop/hdds/tracing/TracingUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java index 938ff1edb017..44a6ff8ccf0e 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java @@ -238,10 +238,10 @@ public static Span importAndCreateSpan(String name, String encodedParent, W3CTraceContextPropagator propagator = W3CTraceContextPropagator.getInstance(); Context extract = propagator.extract(Context.current(), encodedParent, new TextExtractor()); - return tracer.spanBuilder(name). - setParent(extract). - setSpanKind(spanKind). - startSpan(); + return tracer.spanBuilder(name) + .setParent(extract) + .setSpanKind(spanKind) + .startSpan(); } /** From a2a8c61d563df9dd3b79b14ee477143933f42b11 Mon Sep 17 00:00:00 2001 From: sravani-revuri Date: Fri, 10 Jul 2026 20:44:02 +0530 Subject: [PATCH 4/5] added test for kind + comment --- .../hadoop/hdds/tracing/TraceAllMethod.java | 1 + .../hadoop/hdds/tracing/TestTracingUtil.java | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java index 1e5ab249bb25..7afbf698f65f 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java @@ -78,6 +78,7 @@ public Object invoke(Object proxy, Method method, Object[] args) } } + // close() is local cleanup in the shell process, not an outbound RPC to OM/SCM/DN , so it stays INTERNAL. SpanKind spanKind = "close".equals(method.getName()) ? SpanKind.INTERNAL : SpanKind.CLIENT; diff --git a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingUtil.java b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingUtil.java index 4474e8a42c47..17dfd2a61aef 100644 --- a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingUtil.java +++ b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingUtil.java @@ -29,7 +29,9 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.context.Scope; +import io.opentelemetry.sdk.trace.ReadableSpan; import java.io.IOException; import org.apache.hadoop.hdds.conf.InMemoryConfigurationForTesting; import org.apache.hadoop.hdds.conf.MutableConfigurationSource; @@ -67,6 +69,10 @@ private static String parentSpanIdFromExportedCarrier(String parentCarrier) { return parts[2]; } + private static SpanKind spanKind(Span span) { + return ((ReadableSpan) span).getKind(); + } + @Test public void testDefaultMethod() { Service subject = createProxy(new ServiceImpl(), Service.class, @@ -214,4 +220,43 @@ public void testTextExtractorEmptyAndMalformedEntries() { assertEquals("00-a-b-01", ex2.get(carrier, "traceparent")); assertEquals("00-a-b-01", ex2.get(carrier, "traceparent")); } + + @Test + public void testImportAndCreateSpanDefaultsToInternal() { + TracingUtil.initTracing("serviceTestKind", + tracingEnabled().getObject(TracingConfig.class)); + + Span root = TracingUtil.importAndCreateSpan("rootspan", null); + try { + assertEquals(SpanKind.INTERNAL, spanKind(root)); + } finally { + root.end(); + } + + String parent; + try (TracingUtil.TraceCloseable ignored = + TracingUtil.createActivatedSpan("parentSpan")) { + parent = TracingUtil.exportCurrentSpan(); + } + Span child = TracingUtil.importAndCreateSpan("childSpan", parent); + try { + assertEquals(SpanKind.INTERNAL, spanKind(child)); + } finally { + child.end(); + } + } + + @Test + public void testImportAndCreateSpanUsesExplicitKind() { + TracingUtil.initTracing("span-kind-explicit", + tracingEnabled().getObject(TracingConfig.class)); + + Span server = TracingUtil.importAndCreateSpan( + "server", null, SpanKind.SERVER); + try { + assertEquals(SpanKind.SERVER, spanKind(server)); + } finally { + server.end(); + } + } } From 27771b4280416d3c7582f0c7426a20fd30c666d1 Mon Sep 17 00:00:00 2001 From: sravani-revuri Date: Sat, 11 Jul 2026 11:19:03 +0530 Subject: [PATCH 5/5] internal span kind annotation + tests --- .../hadoop/hdds/tracing/InternalSpanKind.java | 33 +++++++ .../hadoop/hdds/tracing/TraceAllMethod.java | 4 +- .../hdds/tracing/TestTraceAllMethod.java | 20 +++++ .../hdds/tracing/TestTracingAnnotations.java | 88 +++++++++++++++++++ .../hadoop/hdds/tracing/TestTracingUtil.java | 32 ------- ...ManagerProtocolClientSideTranslatorPB.java | 3 + 6 files changed, 146 insertions(+), 34 deletions(-) create mode 100644 hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/InternalSpanKind.java create mode 100644 hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingAnnotations.java diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/InternalSpanKind.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/InternalSpanKind.java new file mode 100644 index 000000000000..de34d8fa25d0 --- /dev/null +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/InternalSpanKind.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.hadoop.hdds.tracing; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation that marks a proxied client method as SpanKind.INTERNAL. + * Used for methods that do not send an outbound RPC. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface InternalSpanKind { +} + diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java index 7afbf698f65f..b2d4f8ade736 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TraceAllMethod.java @@ -78,8 +78,8 @@ public Object invoke(Object proxy, Method method, Object[] args) } } - // close() is local cleanup in the shell process, not an outbound RPC to OM/SCM/DN , so it stays INTERNAL. - SpanKind spanKind = "close".equals(method.getName()) + // if a call is within a process, not an outbound RPC to other processes (OM/SCM/DN) , it is marked as INTERNAL. + SpanKind spanKind = delegateMethod.isAnnotationPresent(InternalSpanKind.class) ? SpanKind.INTERNAL : SpanKind.CLIENT; diff --git a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTraceAllMethod.java b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTraceAllMethod.java index f24a54367b31..8c10861d9314 100644 --- a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTraceAllMethod.java +++ b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTraceAllMethod.java @@ -21,6 +21,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.sdk.trace.ReadableSpan; import java.io.IOException; import org.junit.jupiter.api.Test; @@ -54,6 +56,8 @@ default String defaultMethod() { return otherMethod("default"); } + String localMethod(); + String skippedMethod(); void throwingMethod() throws IOException; @@ -69,6 +73,11 @@ default String defaultMethod() { public static class ServiceImpl implements Service { private boolean spanActive = false; + private SpanKind spanKind; + + public SpanKind lastSpanKind() { + return spanKind; + } @Override public String otherMethod(String name) { @@ -95,6 +104,17 @@ public String normalMethod() { return "normal"; } + @Override + @InternalSpanKind + public String localMethod() { + Span span = Span.current(); + this.spanActive = span.getSpanContext().isValid(); + if (spanActive) { + this.spanKind = ((ReadableSpan) span).getKind(); + } + return "local"; + } + public boolean wasSpanActive() { return spanActive; } diff --git a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingAnnotations.java b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingAnnotations.java new file mode 100644 index 000000000000..823758ff93e2 --- /dev/null +++ b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingAnnotations.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.hadoop.hdds.tracing; + +import static org.apache.hadoop.hdds.tracing.TracingUtil.createProxy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.opentelemetry.api.trace.SpanKind; +import java.io.IOException; +import org.apache.hadoop.hdds.conf.InMemoryConfigurationForTesting; +import org.apache.hadoop.hdds.conf.MutableConfigurationSource; +import org.apache.hadoop.hdds.tracing.TestTraceAllMethod.Service; +import org.apache.hadoop.hdds.tracing.TestTraceAllMethod.ServiceImpl; +import org.junit.jupiter.api.Test; + +/** + * Test for Tracing related annotations. + * {@link SkipTracing} , {@link InternalSpanKind}. + */ +public class TestTracingAnnotations { + + private static MutableConfigurationSource tracingEnabled() { + MutableConfigurationSource config = new InMemoryConfigurationForTesting(); + config.setBoolean("ozone.tracing.enabled", true); + return config; + } + + @Test + public void testSkipTracingNoSpan() { + TracingUtil.initTracing("TestService", tracingEnabled()); + ServiceImpl impl = new ServiceImpl(); + Service serviceProxy = createProxy(impl, Service.class, tracingEnabled()); + + serviceProxy.skippedMethod(); + assertFalse(impl.wasSpanActive(), "Span should NOT be created for @SkipTracing methods."); + } + + @Test + public void testSkipTracingExceptionUnwrapped() { + TracingUtil.initTracing("TestService", tracingEnabled()); + ServiceImpl impl = new ServiceImpl(); + Service serviceProxy = createProxy(impl, Service.class, tracingEnabled()); + + IOException ex = assertThrows(IOException.class, + () -> serviceProxy.throwingMethod()); + assertEquals("Original Exception", ex.getMessage()); + assertFalse(impl.wasSpanActive(), "Span should NOT have been created for a @SkipTracing throwing method."); + } + + @Test + public void testProxyNormalVsSkipped() { + TracingUtil.initTracing("TestService", tracingEnabled()); + ServiceImpl impl = new ServiceImpl(); + Service serviceProxy = createProxy(impl, Service.class, tracingEnabled()); + + serviceProxy.normalMethod(); + assertTrue(impl.wasSpanActive(), "Normal method should have an active span."); + } + + @Test + public void testInternalSpanKind() { + TracingUtil.initTracing("TestService", tracingEnabled()); + ServiceImpl impl = new ServiceImpl(); + Service serviceProxy = createProxy(impl, Service.class, tracingEnabled()); + serviceProxy.localMethod(); + assertTrue(impl.wasSpanActive(), "Local method should have an active span."); + assertEquals(SpanKind.INTERNAL, impl.lastSpanKind(), "@InternalSpanKind method should use INTERNAL."); + } + +} diff --git a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingUtil.java b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingUtil.java index 17dfd2a61aef..49bb7a451783 100644 --- a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingUtil.java +++ b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingUtil.java @@ -91,38 +91,6 @@ public void testInitTracing() { } } - @Test - public void testSkipTracingNoSpan() { - TracingUtil.initTracing("TestService", tracingEnabled()); - ServiceImpl impl = new ServiceImpl(); - Service serviceProxy = createProxy(impl, Service.class, tracingEnabled()); - - serviceProxy.skippedMethod(); - assertFalse(impl.wasSpanActive(), "Span should NOT be created for @SkipTracing methods."); - } - - @Test - public void testSkipTracingExceptionUnwrapped() { - TracingUtil.initTracing("TestService", tracingEnabled()); - ServiceImpl impl = new ServiceImpl(); - Service serviceProxy = createProxy(impl, Service.class, tracingEnabled()); - - IOException ex = assertThrows(IOException.class, - () -> serviceProxy.throwingMethod()); - assertEquals("Original Exception", ex.getMessage()); - assertFalse(impl.wasSpanActive(), "Span should NOT have been created for a @SkipTracing throwing method."); - } - - @Test - public void testProxyNormalVsSkipped() { - TracingUtil.initTracing("TestService", tracingEnabled()); - ServiceImpl impl = new ServiceImpl(); - Service serviceProxy = createProxy(impl, Service.class, tracingEnabled()); - - serviceProxy.normalMethod(); - assertTrue(impl.wasSpanActive(), "Normal method should have an active span."); - } - @Test public void testImportAndCreateSpanNullOrEmptyParent() { TracingUtil.initTracing("NoParentService", tracingEnabled().getObject(TracingConfig.class)); diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java index 9de50cd0d352..af66e19be8fc 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java @@ -49,6 +49,7 @@ import org.apache.hadoop.hdds.protocol.proto.HddsProtos.TransferLeadershipRequestProto; import org.apache.hadoop.hdds.protocol.proto.HddsProtos.UpgradeFinalizationStatus; import org.apache.hadoop.hdds.scm.container.common.helpers.ExcludeList; +import org.apache.hadoop.hdds.tracing.InternalSpanKind; import org.apache.hadoop.hdds.tracing.SkipTracing; import org.apache.hadoop.hdds.tracing.TracingUtil; import org.apache.hadoop.io.Text; @@ -295,6 +296,7 @@ public OzoneManagerProtocolClientSideTranslatorPB(OmTransport omTransport, * @throws IOException if an I/O error occurs */ @Override + @InternalSpanKind public void close() throws IOException { //transport is not reusable transport.close(); @@ -2184,6 +2186,7 @@ public void clearThreadLocalS3Auth() { } @Override + @SkipTracing public ThreadLocal getS3CredentialsProvider() { return this.threadLocalS3Auth; }