adoroszlai commented on code in PR #9957:
URL: https://github.com/apache/ozone/pull/9957#discussion_r2988227912


##########
hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/SpanSampler.java:
##########
@@ -0,0 +1,85 @@
+/*
+ * 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 io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import io.opentelemetry.sdk.trace.samplers.SamplingResult;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Custom Sampler that applies span-level sampling for configured
+ * span names, and delegates to parent-based strategy otherwise.
+ * When a span name is in the configured spanMap, uses LoopSampler for
+ * deterministic 1-in-N sampling, otherwise follows the parent span's
+ * sampling decision.
+ */
+public final class SpanSampler implements Sampler {
+
+  private final Sampler rootSampler;
+  private final Map<String, LoopSampler> spanMap;
+
+  public SpanSampler(Sampler rootSampler,
+                     Map<String, LoopSampler> spanMap) {
+    this.rootSampler = rootSampler;
+    this.spanMap = spanMap;
+  }
+
+  @Override
+  public SamplingResult shouldSample(Context parentContext, String traceId,
+                                     String spanName, SpanKind spanKind, 
Attributes attributes,
+                                     
List<io.opentelemetry.sdk.trace.data.LinkData> parentLinks) {

Review Comment:
   nit: Please do not format method signature like this. Whenever visibility / 
return type / method name / other modifiers are changed, we would have to 
reindent all parameters.



##########
hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestSpanSampling.java:
##########
@@ -0,0 +1,156 @@
+/*
+ * 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.assertTrue;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
+import io.opentelemetry.sdk.trace.samplers.SamplingResult;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test cases for span sampling functionality.
+ */
+public class TestSpanSampling {
+
+  /**
+   * Tests that valid configuration strings result in a Map
+   * containing the correct LoopSampler objects.
+   */
+  @Test
+  public void testParseSpanSamplingConfigValid() throws Exception {
+    String config = "createVolume:0.25,createBucket:0.5,createKey:0.75";
+    Method method = 
TracingUtil.class.getDeclaredMethod("parseSpanSamplingConfig", String.class);
+    method.setAccessible(true);
+    Map<String, LoopSampler> result = (Map<String, LoopSampler>) 
method.invoke(null, config);
+
+    // Verify all 3 valid entries exist
+    assertEquals(3, result.size());
+    assertTrue(result.containsKey("createVolume"));
+    assertTrue(result.containsKey("createBucket"));
+    assertTrue(result.containsKey("createKey"));
+  }
+
+  /**
+   * Tests that invalid entries (zeros, negative numbers, non-numeric) are 
caught
+   * by the try-catch blocks and excluded from the resulting Map.
+   */
+  @Test
+  public void testParseSpanSamplingConfigInvalid() throws Exception {
+    String config = 
"createVolume:0,createBucket:-0.5,createKey:invalid,writeKey:-1";
+
+    Method method = 
TracingUtil.class.getDeclaredMethod("parseSpanSamplingConfig", String.class);
+    method.setAccessible(true);
+
+    Map<String, LoopSampler> result = (Map<String, LoopSampler>) 
method.invoke(null, config);
+
+    // Verify the map is empty because every entry was invalid
+    assertTrue(result.isEmpty(), "The map should be empty as all inputs were 
invalid");
+  }
+
+  /**
+   * Tests a mixed configuration to ensure valid entries are
+   * preserved while invalid ones are skipped.
+   */
+  @Test
+  public void testParseSpanSamplingConfigMixed() throws Exception {
+    String config = "createVolume:0.75,createBucket:0,createKey:-5";
+
+    Method method = 
TracingUtil.class.getDeclaredMethod("parseSpanSamplingConfig", String.class);
+    method.setAccessible(true);
+
+    Map<String, LoopSampler> result = (Map<String, LoopSampler>) 
method.invoke(null, config);
+
+    // Verify only createVolume is kept
+    assertEquals(1, result.size());
+    assertTrue(result.containsKey("createVolume"));
+    assertFalse(result.containsKey("createBucket"));
+    assertFalse(result.containsKey("createKey"));

Review Comment:
   nit: for better failure message (see HDDS-9951), please use `assertThat` 
(from `assertj-core`)
   
   ```java
   assertThat(result)
       .containsKey("createVolume")
       .doesNotContainKeys("createBucket", "createKey");
   ```



##########
hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestSpanSampling.java:
##########
@@ -0,0 +1,156 @@
+/*
+ * 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.assertTrue;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
+import io.opentelemetry.sdk.trace.samplers.SamplingResult;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test cases for span sampling functionality.
+ */
+public class TestSpanSampling {
+
+  /**
+   * Tests that valid configuration strings result in a Map
+   * containing the correct LoopSampler objects.
+   */
+  @Test
+  public void testParseSpanSamplingConfigValid() throws Exception {
+    String config = "createVolume:0.25,createBucket:0.5,createKey:0.75";
+    Method method = 
TracingUtil.class.getDeclaredMethod("parseSpanSamplingConfig", String.class);
+    method.setAccessible(true);
+    Map<String, LoopSampler> result = (Map<String, LoopSampler>) 
method.invoke(null, config);
+
+    // Verify all 3 valid entries exist
+    assertEquals(3, result.size());
+    assertTrue(result.containsKey("createVolume"));
+    assertTrue(result.containsKey("createBucket"));
+    assertTrue(result.containsKey("createKey"));
+  }
+
+  /**
+   * Tests that invalid entries (zeros, negative numbers, non-numeric) are 
caught
+   * by the try-catch blocks and excluded from the resulting Map.
+   */
+  @Test
+  public void testParseSpanSamplingConfigInvalid() throws Exception {
+    String config = 
"createVolume:0,createBucket:-0.5,createKey:invalid,writeKey:-1";
+
+    Method method = 
TracingUtil.class.getDeclaredMethod("parseSpanSamplingConfig", String.class);
+    method.setAccessible(true);
+
+    Map<String, LoopSampler> result = (Map<String, LoopSampler>) 
method.invoke(null, config);
+
+    // Verify the map is empty because every entry was invalid
+    assertTrue(result.isEmpty(), "The map should be empty as all inputs were 
invalid");

Review Comment:
   nit: `assertThat(result).isEmpty()`
   
   (If `result` is not empty, `assertTrue` just fails with `expected <true>, 
but was: <false>`, but doesn't provide info on what was unexpectedly present in 
the map.)



##########
hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/SpanSampler.java:
##########
@@ -0,0 +1,85 @@
+/*
+ * 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 io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import io.opentelemetry.sdk.trace.samplers.SamplingResult;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Custom Sampler that applies span-level sampling for configured
+ * span names, and delegates to parent-based strategy otherwise.
+ * When a span name is in the configured spanMap, uses LoopSampler for
+ * deterministic 1-in-N sampling, otherwise follows the parent span's
+ * sampling decision.
+ */
+public final class SpanSampler implements Sampler {
+
+  private final Sampler rootSampler;
+  private final Map<String, LoopSampler> spanMap;
+
+  public SpanSampler(Sampler rootSampler,
+                     Map<String, LoopSampler> spanMap) {
+    this.rootSampler = rootSampler;
+    this.spanMap = spanMap;
+  }
+
+  @Override
+  public SamplingResult shouldSample(Context parentContext, String traceId,
+                                     String spanName, SpanKind spanKind, 
Attributes attributes,
+                                     
List<io.opentelemetry.sdk.trace.data.LinkData> parentLinks) {
+
+    // First, check if we have a valid parent span
+    io.opentelemetry.api.trace.Span parentSpan =
+        io.opentelemetry.api.trace.Span.fromContext(parentContext);

Review Comment:
   Can we add imports for `Span` and other opentelemetry types?



##########
hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/RandomKeyGenerator.java:
##########
@@ -701,26 +705,32 @@ private static class KeyValidate {
   }
 
   private class ObjectCreator implements Runnable {
+    private final Span parentSpan;
+
+    ObjectCreator(Span parentSpan) {
+      this.parentSpan = parentSpan;
+    }
+
     @Override
     public void run() {
-      int v;
-      while ((v = volumeCounter.getAndIncrement()) < numOfVolumes) {
-        if (!createVolume(v)) {
-          return;
+      try (Scope scope = parentSpan.makeCurrent()) {

Review Comment:
   nit: to reduce change due to extra indentation, the original `run()` 
function can be renamed to something like `createObjects()`, and `run()` can 
invoke it inside the new `try` block.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to