This is an automated email from the ASF dual-hosted git repository.
sumitagrawl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 3a450fa0da3 HDDS-13803. Client aware tracing (#10477)
3a450fa0da3 is described below
commit 3a450fa0da36acafe7facd5156b4131be71d1cfb
Author: sravani <[email protected]>
AuthorDate: Fri Jul 31 15:37:40 2026 +0530
HDDS-13803. Client aware tracing (#10477)
---
.../apache/hadoop/hdds/tracing/TracingConfig.java | 16 ++
.../apache/hadoop/hdds/tracing/TracingUtil.java | 191 ++++++++++++++++----
.../hadoop/hdds/tracing/TestTracingInitModes.java | 193 +++++++++++++++++++++
.../apache/hadoop/ozone/client/rpc/RpcClient.java | 3 +-
4 files changed, 371 insertions(+), 32 deletions(-)
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingConfig.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingConfig.java
index ddbc6754379..5fe6dfcdb86 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingConfig.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingConfig.java
@@ -49,6 +49,18 @@ public class TracingConfig extends ReconfigurableConfig {
)
private boolean tracingEnabled;
+ @Config(
+ key = "ozone.tracing.client.application-aware",
+ defaultValue = "true",
+ type = ConfigType.BOOLEAN,
+ reconfigurable = true,
+ tags = { ConfigTag.OZONE, ConfigTag.HDDS },
+ description = "Only effective when ozone.tracing.enabled=false. When
true, Ozone will "
+ + "continue an application-supplied trace (via GlobalOpenTelemetry
or a wire-propagated "
+ + "context) as child spans, but will NOT start a new root trace on
its own."
+ )
+ private boolean applicationAware = true;
+
@Config(
key = "ozone.tracing.endpoint",
defaultValue = "",
@@ -83,6 +95,10 @@ public boolean isTracingEnabled() {
return tracingEnabled;
}
+ public boolean isApplicationAware() {
+ return applicationAware;
+ }
+
@PostConstruct
public void validate() {
if (tracingEndpoint.isEmpty()) {
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 d25817a7a7d..c5624c3c214 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
@@ -17,6 +17,7 @@
package org.apache.hadoop.hdds.tracing;
+import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
@@ -26,12 +27,14 @@
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
+import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
+import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.lang.reflect.Proxy;
import java.util.Collections;
@@ -53,9 +56,12 @@ public final class TracingUtil {
private static final String NULL_SPAN_AS_STRING = "";
private static volatile boolean isInit = false;
+ private static volatile boolean tracingEnabled;
+ private static volatile boolean applicationAware;
private static Tracer tracer = OpenTelemetry.noop().getTracer("noop");
private static volatile SdkTracerProvider sdkTracerProvider;
private static BatchSpanProcessor batchSpanProcessor;
+ public static final String GLOBAL_TRACER_NAME = "ozone";
private TracingUtil() {
}
@@ -65,14 +71,20 @@ private TracingUtil() {
*/
public static synchronized void initTracing(
String serviceName, TracingConfig tracingConfig) {
- if (!tracingConfig.isTracingEnabled() || isInit) {
+ initTracing(serviceName, tracingConfig, false);
+ }
+
+ private static synchronized void initTracing(
+ String serviceName, TracingConfig tracingConfig, boolean isReconfig) {
+ if (isInit) {
return;
}
try {
- initialize(serviceName, tracingConfig);
+ initialize(serviceName, tracingConfig, isReconfig);
isInit = true;
- LOG.info("Initialized tracing service: {}", serviceName);
+ LOG.info("Initialized tracing service: {} (enabled={},
applicationAware={})",
+ serviceName, tracingEnabled, applicationAware);
} catch (Exception e) {
LOG.error("Failed to initialize tracing", e);
}
@@ -94,7 +106,7 @@ public static synchronized void initTracing(
public static synchronized void reconfigureTracing(
String serviceName, TracingConfig tracingConfig) {
shutdownTracing();
- initTracing(serviceName, tracingConfig);
+ initTracing(serviceName, tracingConfig, true);
}
/**
@@ -129,23 +141,107 @@ public static <R, E extends Exception> R execute(
}
}
- private static void shutdownTracing() {
- if (sdkTracerProvider == null) {
- return;
- }
+ static void shutdownTracing() {
try {
- sdkTracerProvider.shutdown().join(10L, TimeUnit.SECONDS);
+ if (sdkTracerProvider != null) {
+ sdkTracerProvider.shutdown().join(10L, TimeUnit.SECONDS);
+ }
} catch (Exception e) {
LOG.warn("Tracing shutdown failed", e);
} finally {
sdkTracerProvider = null;
batchSpanProcessor = null;
tracer = OpenTelemetry.noop().getTracer("noop");
+ tracingEnabled = false;
+ applicationAware = false;
isInit = false;
}
}
- private static void initialize(String serviceName, TracingConfig
tracingConfig) {
+ private static void initialize(String serviceName, TracingConfig cfg,
boolean isReconfig) {
+ tracingEnabled = cfg.isTracingEnabled();
+ applicationAware = cfg.isApplicationAware();
+
+ if (!tracingEnabled && !applicationAware) {
+ tracer = OpenTelemetry.noop().getTracer(GLOBAL_TRACER_NAME);
+ return;
+ }
+
+ // Server reconfiguration reprioritizes Ozone's SDK over any adopted
global,
+ // and re-registers the global name and tracer.
+ if (isReconfig && tracingEnabled) {
+ initOzoneSdk(serviceName, cfg, true);
+ return;
+ }
+
+ // Global first: adopt an application-registered GlobalOpenTelemetry when
present.
+ if (GlobalOpenTelemetry.isSet() &&
isRealGlobal(GlobalOpenTelemetry.get())) {
+ tracer = GlobalOpenTelemetry.get().getTracer(GLOBAL_TRACER_NAME);
+ LOG.info("Tracing: adopted application GlobalOpenTelemetry");
+ return;
+ }
+
+ // No app-supplied global — build Ozone's SDK and always register it as
the JVM global,
+ // so any co-resident library observes the same tracer whenever tracing is
valid.
+ initOzoneSdk(serviceName, cfg, true);
+ }
+
+ private static void initOzoneSdk(String serviceName, TracingConfig cfg,
boolean registerGlobal) {
+ SdkTracerProvider tracerProvider = buildSdkTracerProvider(serviceName,
cfg);
+ try {
+ OpenTelemetrySdk sdk;
+ if (registerGlobal) {
+ sdk = OpenTelemetrySdk.builder()
+ .setTracerProvider(tracerProvider)
+
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
+ .build();
+ if (!GlobalOpenTelemetry.isSet() ||
!isRealGlobal(GlobalOpenTelemetry.get())) {
+ GlobalOpenTelemetry.set(sdk);
+ }
+ tracer = GlobalOpenTelemetry.get().getTracer(GLOBAL_TRACER_NAME);
+ } else {
+ sdk = OpenTelemetrySdk.builder()
+ .setTracerProvider(tracerProvider)
+ .build();
+ tracer = sdk.getTracer(GLOBAL_TRACER_NAME);
+ }
+ sdkTracerProvider = tracerProvider;
+ } catch (RuntimeException e) {
+ tracerProvider.shutdown();
+ batchSpanProcessor = null;
+ throw e;
+ }
+ }
+
+ /**
+ * Distinguish an application-registered GlobalOpenTelemetry from the OTel
built-in noop.
+ * OpenTelemetry.noop() returns a singleton, so identity comparison is
sufficient.
+ */
+ private static boolean isRealGlobal(OpenTelemetry global) {
+ return global != null && global != OpenTelemetry.noop();
+ }
+
+ /**
+ * Whether to wrap the delegate in a JDK tracing proxy.
+ * Fully enabled: always wrap. App-aware: wrap only when parent span is valid
+ */
+ private static boolean shouldCreateTracingProxy(ConfigurationSource conf) {
+ TracingConfig tc = conf.getObject(TracingConfig.class);
+ if (tc.isTracingEnabled()) {
+ return true;
+ }
+ if (!tc.isApplicationAware() || !hasUsableTracer()) {
+ return false;
+ }
+ return Span.current().getSpanContext().isValid();
+ }
+
+ /**
+ * Build the SdkTracerProvider using the configured OTLP endpoint and
sampler.
+ * Extracted so both enabled and application-aware modes share
exporter/sampler setup.
+ */
+ private static SdkTracerProvider buildSdkTracerProvider(
+ String serviceName, TracingConfig tracingConfig) {
//Fetch and log the right tracing parameters based on config, environment
variable and default value priority.
String otelEndPoint = tracingConfig.getTracingEndpoint();
double samplerRatio = tracingConfig.getTraceSamplerRatio();
@@ -156,7 +252,7 @@ private static void initialize(String serviceName,
TracingConfig tracingConfig)
Map<String, LoopSampler> spanMap =
parseSpanSamplingConfig(spanSamplingConfig);
Resource resource =
Resource.create(Attributes.of(AttributeKey.stringKey("service.name"),
serviceName));
- OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder()
+ SpanExporter spanExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint(otelEndPoint)
.build();
@@ -172,36 +268,30 @@ private static void initialize(String serviceName,
TracingConfig tracingConfig)
sampler = new SpanSampler(rootSampler, spanMap);
}
- SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
+ return SdkTracerProvider.builder()
.addSpanProcessor(batchSpanProcessor)
.setResource(resource)
.setSampler(sampler)
.build();
+ }
- try {
- OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
- .setTracerProvider(tracerProvider)
- .build();
- tracer = openTelemetry.getTracer(serviceName);
- sdkTracerProvider = tracerProvider;
- } catch (RuntimeException e) {
- tracerProvider.shutdown();
- batchSpanProcessor = null;
- throw e;
- }
+ private static boolean canStartSpanWithoutParent() {
+ return tracingEnabled;
}
/**
* Export the active tracing span as a string.
+ * When tracing is disabled, not initialized, or no valid span is in scope,
+ * {@link Span#current()} returns an invalid span; there is nothing to
encode and this
+ * method returns an empty string. Callers must accept that as "no context
to propagate".
*
- * @return encoded tracing context.
+ * @return encoded W3C trace context, or empty string if there is no valid
active span.
*/
public static String exportCurrentSpan() {
Span currentSpan = Span.current();
if (!currentSpan.getSpanContext().isValid()) {
return NULL_SPAN_AS_STRING;
}
-
StringBuilder builder = new StringBuilder();
W3CTraceContextPropagator propagator =
W3CTraceContextPropagator.getInstance();
propagator.inject(Context.current(), builder,
@@ -211,13 +301,23 @@ public static String exportCurrentSpan() {
/**
* Create a new scope and use the imported span as the parent.
+ * Short-circuits to an invalid span when there is no usable tracer:
+ * - tracing was never initialized (tracer is still the noop), or
+ * - application-aware mode is on but no app-supplied SDK was adopted
(sdkTracerProvider == null
+ * and the current tracer is the noop).
*
* @param name name of the newly created scope
* @param encodedParent Encoded parent span (could be null or empty)
* @return Tracing scope.
*/
public static Span importAndCreateSpan(String name, String encodedParent) {
+ if (!hasUsableTracer()) {
+ return Span.getInvalid();
+ }
if (encodedParent == null || encodedParent.isEmpty()) {
+ if (!canStartSpanWithoutParent()) {
+ return Span.getInvalid();
+ }
return tracer.spanBuilder(name).setNoParent().startSpan();
}
@@ -228,6 +328,17 @@ public static Span importAndCreateSpan(String name, String
encodedParent) {
.startSpan();
}
+ /**
+ * True when the current tracer can actually build spans — an Ozone-owned
SDK is configured,
+ * or an adopted GlobalOpenTelemetry provides a non-noop tracer.
+ */
+ private static boolean hasUsableTracer() {
+ if (sdkTracerProvider != null) {
+ return true;
+ }
+ return GlobalOpenTelemetry.isSet() &&
isRealGlobal(GlobalOpenTelemetry.get());
+ }
+
/**
* Creates a proxy of the implementation and trace all the method calls.
*
@@ -241,7 +352,7 @@ public static Span importAndCreateSpan(String name, String
encodedParent) {
*/
public static <T> T createProxy(
T delegate, Class<T> itf, ConfigurationSource conf) {
- if (!isTracingEnabled(conf)) {
+ if (!shouldCreateTracingProxy(conf)) {
return delegate;
}
Class<?> aClass = delegate.getClass();
@@ -254,6 +365,20 @@ public static boolean isTracingEnabled(ConfigurationSource
conf) {
return conf.getObject(TracingConfig.class).isTracingEnabled();
}
+ /**
+ * Returns true when tracing may actually produce spans:
+ * - fully enabled (ozone.tracing.enabled=true), or
+ * - application-aware AND an SDK is configured (either Ozone-owned or an
adopted global);
+ * without an SDK, application-aware is a passthrough that would emit
noop spans anyway.
+ */
+ public static boolean isTracingActive(ConfigurationSource conf) {
+ TracingConfig tc = conf.getObject(TracingConfig.class);
+ if (tc.isTracingEnabled()) {
+ return true;
+ }
+ return tc.isApplicationAware() && hasUsableTracer();
+ }
+
/**
* Function to parse span sampling config. The input is in the form
<span_name>:<sample_rate>.
* The sample rate must be a number between 0 and 1. Any value other than
that will LOG an error.
@@ -419,7 +544,8 @@ private void parse(String carrier) {
/**
* Creates a new span, using the current context as a parent if valid;
- * otherwise, creates a root span.
+ * Otherwise starts a root span only when {@code ozone.tracing.enabled=true};
+ * if not, returns an invalid span so application-aware mode never starts a
new trace.
*/
private static Span buildSpan(String spanName) {
Context currentContext = Context.current();
@@ -427,9 +553,11 @@ private static Span buildSpan(String spanName) {
if (parentSpan.getSpanContext().isValid()) {
return
tracer.spanBuilder(spanName).setParent(currentContext).startSpan();
- } else {
- return tracer.spanBuilder(spanName).setNoParent().startSpan();
}
+ if (!canStartSpanWithoutParent()) {
+ return Span.getInvalid();
+ }
+ return tracer.spanBuilder(spanName).setNoParent().startSpan();
}
/**
@@ -451,7 +579,7 @@ public String get(Function<String, String> carrier, String
key) {
public static TraceCloseable createActivatedSpanFromW3cHttpHeaders(
String spanName, Function<String, String> getHeader, ConfigurationSource
conf) {
- if (conf == null || !isTracingEnabled(conf)) {
+ if (conf == null || !isTracingActive(conf)) {
return () -> { };
}
@@ -459,6 +587,9 @@ public static TraceCloseable
createActivatedSpanFromW3cHttpHeaders(
.extract(Context.current(), getHeader, new HttpHeaderGetter());
if (!Span.fromContext(remote).getSpanContext().isValid()) {
+ if (!canStartSpanWithoutParent()) {
+ return () -> { };
+ }
return createActivatedSpan(spanName);
}
diff --git
a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingInitModes.java
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingInitModes.java
new file mode 100644
index 00000000000..ae06a82a0d4
--- /dev/null
+++
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestTracingInitModes.java
@@ -0,0 +1,193 @@
+/*
+ * 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.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.context.Scope;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.trace.SdkTracerProvider;
+import org.apache.hadoop.hdds.conf.InMemoryConfigurationForTesting;
+import org.apache.hadoop.hdds.conf.MutableConfigurationSource;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests tracing init for enabled, application-aware configs.
+ */
+public class TestTracingInitModes {
+
+ /** Reset tracing state before each test. */
+ @BeforeEach
+ public void resetGlobalState() {
+ TracingUtil.shutdownTracing();
+ GlobalOpenTelemetry.resetForTest();
+ }
+
+ /** Tear down tracing state after each test. */
+ @AfterEach
+ public void cleanup() {
+ TracingUtil.shutdownTracing();
+ GlobalOpenTelemetry.resetForTest();
+ }
+
+ /**
+ * Puts a real GlobalOpenTelemetry in place with no exporter, so tests stay
offline.
+ */
+ private static void installNoExportGlobalOpenTelemetry() {
+ SdkTracerProvider provider = SdkTracerProvider.builder().build();
+ OpenTelemetrySdk sdk =
OpenTelemetrySdk.builder().setTracerProvider(provider).build();
+ GlobalOpenTelemetry.set(sdk);
+ }
+
+ /** Builds in-memory config with enabled and application-aware flags. */
+ private static MutableConfigurationSource config(boolean enabled, boolean
applicationAware) {
+ MutableConfigurationSource conf = new InMemoryConfigurationForTesting();
+ conf.setBoolean("ozone.tracing.enabled", enabled);
+ conf.setBoolean("ozone.tracing.client.application-aware",
applicationAware);
+ return conf;
+ }
+
+ /**
+ * With tracing enabled, Ozone can start its own root span.
+ */
+ @Test
+ public void testEnabledModeStartsRootSpans() {
+ installNoExportGlobalOpenTelemetry();
+ MutableConfigurationSource conf = config(true, true);
+ TracingUtil.initTracing("enabled-svc", conf);
+ assertTrue(TracingUtil.isTracingActive(conf));
+
+ try (TracingUtil.TraceCloseable ignored =
TracingUtil.createActivatedSpan("root")) {
+ assertTrue(Span.current().getSpanContext().isValid(),
+ "Enabled tracing should produce a valid root span");
+ }
+ }
+
+ /** app-aware, no app tracer: active but no root span without a parent. */
+ @Test
+ public void testApplicationAwareWithoutGlobalDoesNotStartRoot() {
+ installNoExportGlobalOpenTelemetry();
+ MutableConfigurationSource conf = config(false, true);
+ TracingUtil.initTracing("app-aware-svc", conf);
+ assertTrue(TracingUtil.isTracingActive(conf));
+
+ try (TracingUtil.TraceCloseable ignored =
TracingUtil.createActivatedSpan("root")) {
+ assertFalse(Span.current().getSpanContext().isValid(),
+ "Application-aware mode must NOT manufacture a root span");
+ }
+ }
+
+ /** app-aware + W3C parent on the wire: child span is created. */
+ @Test
+ public void testApplicationAwareExtendsExtractedContext() {
+ SdkTracerProvider provider = SdkTracerProvider.builder().build();
+ OpenTelemetrySdk external =
OpenTelemetrySdk.builder().setTracerProvider(provider).build();
+
+ Span external1 =
external.getTracer("external").spanBuilder("external-root").startSpan();
+ String parentCarrier;
+ try (Scope ignored = external1.makeCurrent()) {
+ parentCarrier = TracingUtil.exportCurrentSpan();
+ } finally {
+ external1.end();
+ }
+ provider.shutdown();
+ assertFalse(parentCarrier.isEmpty(), "exported carrier should be
non-empty");
+
+ GlobalOpenTelemetry.resetForTest();
+ installNoExportGlobalOpenTelemetry();
+
+ MutableConfigurationSource conf = config(false, true);
+ TracingUtil.initTracing("app-aware-extract", conf);
+ assertTrue(TracingUtil.isTracingActive(conf));
+
+ Span child = TracingUtil.importAndCreateSpan("child", parentCarrier);
+ try (Scope ignored = child.makeCurrent()) {
+ assertTrue(child.getSpanContext().isValid(),
+ "Application-aware mode should honor a wire-propagated parent
context");
+ } finally {
+ child.end();
+ }
+ }
+
+ /** app-aware + GlobalOpenTelemetry set: still no root span without a
parent. */
+ @Test
+ public void testApplicationAwareAdoptsGlobalTracer() {
+ SdkTracerProvider provider = SdkTracerProvider.builder().build();
+ OpenTelemetrySdk appGlobal =
OpenTelemetrySdk.builder().setTracerProvider(provider).build();
+ GlobalOpenTelemetry.set(appGlobal);
+
+ MutableConfigurationSource conf = config(false, true);
+ TracingUtil.initTracing("adopt-global", conf);
+ assertTrue(TracingUtil.isTracingActive(conf));
+
+ try (TracingUtil.TraceCloseable ignored =
TracingUtil.createActivatedSpan("root")) {
+ assertFalse(Span.current().getSpanContext().isValid(),
+ "Application-aware (with adopted global) must NOT manufacture a root
span");
+ }
+ provider.shutdown();
+ }
+
+ /** Both flags false: tracing is off. */
+ @Test
+ public void testOffModeIsInactive() {
+ MutableConfigurationSource conf = config(false, false);
+ TracingUtil.initTracing("off-svc", conf);
+ assertFalse(TracingUtil.isTracingActive(conf),
+ "With both flags false, tracing must be inactive");
+
+ try (TracingUtil.TraceCloseable ignored =
TracingUtil.createActivatedSpan("root")) {
+ assertFalse(Span.current().getSpanContext().isValid(),
+ "Inactive tracing must not produce a valid span");
+ }
+ }
+
+ /** Reconfig from app-aware to enabled activates tracing. */
+ @Test
+ public void testReconfigureFromAppAwareToEnabled() {
+ installNoExportGlobalOpenTelemetry();
+ MutableConfigurationSource conf = config(false, true);
+ TracingUtil.initTracing("reconfig", conf);
+ assertTrue(TracingUtil.isTracingActive(conf));
+
+ try (TracingUtil.TraceCloseable ignored =
TracingUtil.createActivatedSpan("root")) {
+ assertFalse(Span.current().getSpanContext().isValid(),
+ "Application-aware mode must not manufacture a root span");
+ }
+
+ MutableConfigurationSource newConf = config(true, true);
+ TracingUtil.reconfigureTracing("reconfig",
newConf.getObject(TracingConfig.class));
+ assertTrue(TracingUtil.isTracingActive(newConf),
+ "After reconfigure to enabled, tracing must be active");
+ }
+
+ /** OpenTelemetry.noop() is a singleton — used to detect a real app global.
*/
+ @Test
+ public void testNoopSingletonIdentity() {
+ assertEquals(OpenTelemetry.noop(), OpenTelemetry.noop());
+ assertNotEquals(OpenTelemetry.noop(),
+
OpenTelemetrySdk.builder().setTracerProvider(SdkTracerProvider.builder().build()).build());
+ }
+}
diff --git
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
index 62ef6de4f63..893fc90138c 100644
---
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
+++
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
@@ -240,6 +240,7 @@ public RpcClient(ConfigurationSource conf, String
omServiceId)
throws IOException {
Objects.requireNonNull(conf, "conf == null");
this.conf = conf;
+ TracingUtil.initTracing("client", conf);
this.ugi = UserGroupInformation.getCurrentUser();
replicationConfigValidator =
this.conf.getObject(ReplicationConfigValidator.class);
@@ -338,8 +339,6 @@ public void onRemoval(
OZONE_CLIENT_SERVER_DEFAULTS_VALIDITY_PERIOD_MS,
OZONE_CLIENT_SERVER_DEFAULTS_VALIDITY_PERIOD_MS_DEFAULT,
TimeUnit.MILLISECONDS);
-
- TracingUtil.initTracing("client", conf);
}
public XceiverClientFactory getXceiverClientManager() {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]