Skip to content

Commit 73c7be1

Browse files
authored
[dynamic control] Move to using SourceWrapper, simplifying parsing (#2708)
1 parent 49facd4 commit 73c7be1

File tree

2 files changed

+123
-36
lines changed

2 files changed

+123
-36
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.dynamic.policy;
7+
8+
import com.fasterxml.jackson.databind.JsonNode;
9+
import io.opentelemetry.contrib.dynamic.policy.source.JsonSourceWrapper;
10+
import io.opentelemetry.contrib.dynamic.policy.source.KeyValueSourceWrapper;
11+
import io.opentelemetry.contrib.dynamic.policy.source.SourceFormat;
12+
import io.opentelemetry.contrib.dynamic.policy.source.SourceWrapper;
13+
import javax.annotation.Nullable;
14+
15+
/** Base validator with common source-dispatch and parse helpers. */
16+
public abstract class AbstractSourcePolicyValidator implements PolicyValidator {
17+
18+
@Override
19+
@Nullable
20+
public final TelemetryPolicy validate(SourceWrapper source) {
21+
if (source == null) {
22+
return null;
23+
}
24+
SourceFormat format = source.getFormat();
25+
switch (format) {
26+
case JSON: // transitional: same payload shape as JSONKEYVALUE until JSON is removed
27+
case JSONKEYVALUE:
28+
return validateJsonSource(((JsonSourceWrapper) source).asJsonNode());
29+
case KEYVALUE:
30+
return validateKeyValueSource((KeyValueSourceWrapper) source);
31+
}
32+
return null;
33+
}
34+
35+
@Nullable
36+
private TelemetryPolicy validateJsonSource(JsonNode node) {
37+
JsonNode valueNode = node.get(getPolicyType());
38+
if (valueNode == null) {
39+
return null;
40+
}
41+
return validateJsonValue(valueNode);
42+
}
43+
44+
@Nullable
45+
private TelemetryPolicy validateKeyValueSource(KeyValueSourceWrapper source) {
46+
if (!getPolicyType().equals(source.getKey().trim())) {
47+
return null;
48+
}
49+
return validateKeyValueValue(source.getValue());
50+
}
51+
52+
@Nullable
53+
protected abstract TelemetryPolicy validateJsonValue(JsonNode valueNode);
54+
55+
@Nullable
56+
protected abstract TelemetryPolicy validateKeyValueValue(String value);
57+
58+
@Nullable
59+
protected static Double parseDouble(JsonNode valueNode) {
60+
if (valueNode.isNumber()) {
61+
return valueNode.asDouble();
62+
}
63+
if (valueNode.isTextual()) {
64+
return parseDouble(valueNode.asText());
65+
}
66+
return null;
67+
}
68+
69+
@Nullable
70+
protected static Double parseDouble(String value) {
71+
try {
72+
return Double.parseDouble(value.trim());
73+
} catch (NumberFormatException e) {
74+
return null;
75+
}
76+
}
77+
78+
@Nullable
79+
protected static Boolean parseBoolean(JsonNode valueNode) {
80+
if (valueNode.isBoolean()) {
81+
return valueNode.asBoolean();
82+
}
83+
if (valueNode.isTextual()) {
84+
return parseBoolean(valueNode.asText());
85+
}
86+
return null;
87+
}
88+
89+
@Nullable
90+
protected static Boolean parseBoolean(String value) {
91+
String normalized = value.trim();
92+
if ("true".equalsIgnoreCase(normalized)) {
93+
return true;
94+
}
95+
if ("false".equalsIgnoreCase(normalized)) {
96+
return false;
97+
}
98+
return null;
99+
}
100+
}

dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/LinePerPolicyFileProvider.java

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
package io.opentelemetry.contrib.dynamic.policy;
77

8+
import io.opentelemetry.contrib.dynamic.policy.source.SourceFormat;
9+
import io.opentelemetry.contrib.dynamic.policy.source.SourceWrapper;
810
import java.io.IOException;
911
import java.nio.file.Files;
1012
import java.nio.file.Path;
@@ -18,14 +20,13 @@
1820
* A {@link PolicyProvider} that reads policies from a local file, where each line represents a
1921
* separate policy configuration.
2022
*
21-
* <p>The file format supports two types of lines:
23+
* <p>The file format supports JSON and key-value lines:
2224
*
2325
* <ul>
2426
* <li><b>JSON Objects:</b> Lines starting with <code>{</code> are treated as JSON objects and
2527
* validated against the registered {@link PolicyValidator}s.
26-
* <li><b>Key-Value Pairs:</b> Lines in the format <code>key=value</code> are treated as aliases,
27-
* where the key matches a validator's {@link PolicyValidator#getAlias()} and the value is
28-
* parsed accordingly.
28+
* <li><b>Key-Value:</b> Lines containing <code>=</code> are treated as key-value policy lines and
29+
* validated against the registered {@link PolicyValidator}s.
2930
* </ul>
3031
*
3132
* <p>Empty lines and lines starting with <code>#</code> are ignored.
@@ -57,47 +58,33 @@ public List<TelemetryPolicy> fetchPolicies() throws IOException {
5758
return;
5859
}
5960

60-
TelemetryPolicy policy = null;
61-
61+
SourceFormat format;
6262
if (trimmedLine.startsWith("{")) {
63-
for (PolicyValidator validator : validators) {
64-
if (trimmedLine.contains("\"" + validator.getPolicyType() + "\"")) {
65-
policy = validator.validate(trimmedLine);
66-
if (policy != null) {
67-
break;
68-
}
69-
}
70-
}
63+
format = SourceFormat.JSON;
64+
} else if (trimmedLine.indexOf('=') >= 0) {
65+
format = SourceFormat.KEYVALUE;
7166
} else {
72-
int idx = trimmedLine.indexOf('=');
73-
if (idx > 0) {
74-
String key = trimmedLine.substring(0, idx).trim();
75-
String valueStr = trimmedLine.substring(idx + 1).trim();
67+
logger.info("Unsupported policy line format: " + trimmedLine);
68+
return;
69+
}
70+
List<SourceWrapper> parsedSources = format.parse(trimmedLine);
71+
if (parsedSources == null || parsedSources.size() != 1) {
72+
logger.info("Invalid " + format.configValue() + " policy line: " + trimmedLine);
73+
return;
74+
}
7675

77-
for (PolicyValidator validator : validators) {
78-
String alias = validator.getAlias();
79-
if (alias != null && alias.equals(key)) {
80-
try {
81-
policy = validator.validateAlias(key, valueStr);
82-
} catch (UnsupportedOperationException e) {
83-
logger.info(
84-
"Validator does not support alias validation: "
85-
+ validator.getClass().getName());
86-
continue;
87-
}
88-
if (policy != null) {
89-
break;
90-
}
91-
}
92-
}
76+
SourceWrapper parsedSource = parsedSources.get(0);
77+
TelemetryPolicy policy = null;
78+
for (PolicyValidator validator : validators) {
79+
policy = validator.validate(parsedSource);
80+
if (policy != null) {
81+
break;
9382
}
9483
}
95-
9684
if (policy == null) {
9785
logger.info("Validator not found or rejected for line: " + trimmedLine);
9886
return;
9987
}
100-
10188
policies.add(policy);
10289
});
10390
}

0 commit comments

Comments
 (0)