diff --git a/dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/PolicyValidator.java b/dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/PolicyValidator.java new file mode 100644 index 000000000..e48fc3325 --- /dev/null +++ b/dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/PolicyValidator.java @@ -0,0 +1,56 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.dynamic.policy; + +import javax.annotation.Nullable; + +public interface PolicyValidator { + /** + * Validates a policy configuration provided as a JSON string. + * + * @param json The JSON string containing the policy configuration. + * @return The validated {@link TelemetryPolicy}, or {@code null} if the JSON does not contain a + * valid policy for this validator. + */ + @Nullable + TelemetryPolicy validate(String json); + + /** + * Returns the type of the policy this validator handles. + * + * @return The policy type string (e.g., "trace-sampling"). + */ + String getPolicyType(); + + /** + * Validates a policy configuration provided as a key-value pair (alias). + * + *
This is intended for simple configuration cases where a full JSON object is not necessary. + * + * @param key The alias key (e.g., "trace-sampling.probability"). + * @param value The value associated with the key. + * @return The validated {@link TelemetryPolicy}, or {@code null} if the key/value pair is invalid + * or not handled by this validator. + */ + @Nullable + default TelemetryPolicy validateAlias(String key, String value) { + throw new UnsupportedOperationException( + "Alias validation is not supported by validator " + + getClass().getName() + + " for key " + + key); + } + + /** + * Returns the alias key supported by this validator, if any. + * + * @return The alias key string, or {@code null} if aliases are not supported. + */ + @Nullable + default String getAlias() { + return null; + } +} diff --git a/dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/TraceSamplingValidator.java b/dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/TraceSamplingValidator.java new file mode 100644 index 000000000..1279e4731 --- /dev/null +++ b/dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/TraceSamplingValidator.java @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.dynamic.policy; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * Validator for trace sampling policies. + * + *
This validator handles the "trace-sampling" policy type and supports the + * "trace-sampling.probability" alias. + */ +public final class TraceSamplingValidator implements PolicyValidator { + private static final Logger logger = Logger.getLogger(TraceSamplingValidator.class.getName()); + private static final ObjectMapper MAPPER = new ObjectMapper(); + + @Override + public String getPolicyType() { + return "trace-sampling"; + } + + @Override + public String getAlias() { + return "trace-sampling.probability"; + } + + @Override + @Nullable + public TelemetryPolicy validate(String json) { + try { + JsonNode node = MAPPER.readTree(json); + if (node.has(getPolicyType())) { + JsonNode spec = node.get(getPolicyType()); + if (spec.has("probability")) { + JsonNode probNode = spec.get("probability"); + if (probNode.isNumber()) { + double d = probNode.asDouble(); + if (d >= 0.0 && d <= 1.0) { + return new TelemetryPolicy(getPolicyType(), spec); + } + } + } + } + } catch (JsonProcessingException e) { + // Not valid JSON for this validator + } + logger.info("Invalid trace-sampling JSON: " + json); + return null; + } + + @Override + @Nullable + public TelemetryPolicy validateAlias(String key, String value) { + if (getAlias() != null && getAlias().equals(key)) { + try { + double d = Double.parseDouble(value); + if (d >= 0.0 && d <= 1.0) { + JsonNode spec = MAPPER.createObjectNode().put("probability", d); + return new TelemetryPolicy(getPolicyType(), spec); + } + } catch (NumberFormatException e) { + // invalid + } + logger.info("Ignoring invalid trace-sampling.probability value: " + value); + } + return null; + } +}