Skip to content

Commit c457855

Browse files
committed
Add pipeline config initialization from file
1 parent d79c574 commit c457855

2 files changed

Lines changed: 214 additions & 0 deletions

File tree

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,28 @@
55

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

8+
import io.opentelemetry.contrib.dynamic.policy.registry.json.JsonPolicyInitConfigReader;
9+
import io.opentelemetry.contrib.dynamic.policy.registry.yaml.YamlPolicyInitConfigReader;
10+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
11+
import java.io.IOException;
12+
import java.io.InputStream;
13+
import java.nio.file.Files;
14+
import java.nio.file.Paths;
815
import java.util.ArrayList;
916
import java.util.Collections;
1017
import java.util.List;
1118
import java.util.Objects;
19+
import java.util.logging.Level;
20+
import java.util.logging.Logger;
21+
import javax.annotation.Nullable;
1222

1323
/** Top-level registry initialization model containing per-source mapping config. */
1424
public final class PolicyInitConfig {
25+
static final String POLICY_INIT_CONFIG_PROPERTY_JSON =
26+
"otel.java.experimental.telemetry.policy.init.json";
27+
static final String POLICY_INIT_CONFIG_PROPERTY_YAML =
28+
"otel.java.experimental.telemetry.policy.init.yaml";
29+
private static final Logger logger = Logger.getLogger(PolicyInitConfig.class.getName());
1530

1631
private final List<PolicySourceConfig> sources;
1732

@@ -28,6 +43,49 @@ public List<PolicySourceConfig> getSources() {
2843
return sources;
2944
}
3045

46+
/**
47+
* Reads policy-init configuration based on config properties.
48+
*
49+
* <p>YAML takes precedence over JSON when both are present.
50+
*
51+
* @param config OpenTelemetry config properties
52+
* @return parsed init config, or null when no init-config path is configured
53+
* @throws NullPointerException if config is null
54+
*/
55+
@Nullable
56+
public static PolicyInitConfig readFromConfigProperties(ConfigProperties config) {
57+
Objects.requireNonNull(config, "config cannot be null");
58+
String mappingPathYaml = config.getString(POLICY_INIT_CONFIG_PROPERTY_YAML);
59+
if (mappingPathYaml == null || mappingPathYaml.trim().isEmpty()) {
60+
String mappingPathJson = config.getString(POLICY_INIT_CONFIG_PROPERTY_JSON);
61+
if (mappingPathJson == null || mappingPathJson.trim().isEmpty()) {
62+
return null;
63+
} else {
64+
try (InputStream in = Files.newInputStream(Paths.get(mappingPathJson.trim()))) {
65+
return JsonPolicyInitConfigReader.read(in);
66+
} catch (IOException | RuntimeException e) {
67+
logger.log(
68+
Level.WARNING,
69+
"Failed to load telemetry policy init config from {0}",
70+
mappingPathJson.trim());
71+
logger.log(Level.WARNING, "Policy init config read failed", e);
72+
return null;
73+
}
74+
}
75+
} else {
76+
try (InputStream in = Files.newInputStream(Paths.get(mappingPathYaml.trim()))) {
77+
return YamlPolicyInitConfigReader.read(in);
78+
} catch (IOException | RuntimeException e) {
79+
logger.log(
80+
Level.WARNING,
81+
"Failed to load telemetry policy init config from {0}",
82+
mappingPathYaml.trim());
83+
logger.log(Level.WARNING, "Policy init config read failed", e);
84+
return null;
85+
}
86+
}
87+
}
88+
3189
@Override
3290
public boolean equals(Object obj) {
3391
if (this == obj) {
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.dynamic.policy.registry;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.mockito.Mockito.mock;
10+
import static org.mockito.Mockito.when;
11+
12+
import io.opentelemetry.contrib.dynamic.policy.source.SourceFormat;
13+
import io.opentelemetry.contrib.dynamic.policy.source.SourceKind;
14+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
15+
import java.nio.charset.StandardCharsets;
16+
import java.nio.file.Files;
17+
import java.nio.file.Path;
18+
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.api.io.TempDir;
20+
21+
class PolicyInitConfigTest {
22+
23+
@TempDir Path tempDir;
24+
25+
@Test
26+
void readFromConfigPropertiesReturnsNullWhenBothPathsMissing() {
27+
ConfigProperties config = mock(ConfigProperties.class);
28+
when(config.getString(PolicyInitConfig.POLICY_INIT_CONFIG_PROPERTY_YAML)).thenReturn(null);
29+
when(config.getString(PolicyInitConfig.POLICY_INIT_CONFIG_PROPERTY_JSON)).thenReturn(null);
30+
31+
assertThat(PolicyInitConfig.readFromConfigProperties(config)).isNull();
32+
}
33+
34+
@Test
35+
void readFromConfigPropertiesPrefersYamlWhenBothPathsPresent() throws Exception {
36+
Path jsonPath = tempDir.resolve("policy-init.json");
37+
Files.write(jsonPath, jsonWithLocation("from-json").getBytes(StandardCharsets.UTF_8));
38+
Path yamlPath = tempDir.resolve("policy-init.yaml");
39+
Files.write(yamlPath, yamlWithLocation("from-yaml").getBytes(StandardCharsets.UTF_8));
40+
41+
ConfigProperties config = mock(ConfigProperties.class);
42+
when(config.getString(PolicyInitConfig.POLICY_INIT_CONFIG_PROPERTY_YAML))
43+
.thenReturn(yamlPath.toString());
44+
when(config.getString(PolicyInitConfig.POLICY_INIT_CONFIG_PROPERTY_JSON))
45+
.thenReturn(jsonPath.toString());
46+
47+
PolicyInitConfig initConfig = PolicyInitConfig.readFromConfigProperties(config);
48+
49+
assertThat(initConfig).isNotNull();
50+
assertThat(initConfig.getSources()).hasSize(1);
51+
assertThat(initConfig.getSources().get(0).getLocation()).isEqualTo("from-yaml");
52+
}
53+
54+
@Test
55+
void readFromConfigPropertiesFallsBackToJsonWhenYamlBlank() throws Exception {
56+
Path jsonPath = tempDir.resolve("policy-init.json");
57+
Files.write(jsonPath, jsonWithLocation("from-json").getBytes(StandardCharsets.UTF_8));
58+
59+
ConfigProperties config = mock(ConfigProperties.class);
60+
when(config.getString(PolicyInitConfig.POLICY_INIT_CONFIG_PROPERTY_YAML)).thenReturn(" ");
61+
when(config.getString(PolicyInitConfig.POLICY_INIT_CONFIG_PROPERTY_JSON))
62+
.thenReturn(jsonPath.toString());
63+
64+
PolicyInitConfig initConfig = PolicyInitConfig.readFromConfigProperties(config);
65+
66+
assertThat(initConfig).isNotNull();
67+
assertThat(initConfig.getSources()).hasSize(1);
68+
assertThat(initConfig.getSources().get(0).getLocation()).isEqualTo("from-json");
69+
}
70+
71+
@Test
72+
void readFromConfigPropertiesReadsJsonWhenYamlPathMissing() throws Exception {
73+
Path configPath = tempDir.resolve("policy-init.json");
74+
Files.write(configPath, minimalJsonConfig().getBytes(StandardCharsets.UTF_8));
75+
76+
PolicyInitConfig config = configFromPaths(null, configPath.toString());
77+
78+
assertThat(config.getSources()).hasSize(1);
79+
PolicySourceConfig source = config.getSources().get(0);
80+
assertThat(source.getKind()).isEqualTo(SourceKind.OPAMP);
81+
assertThat(source.getFormat()).isEqualTo(SourceFormat.JSONKEYVALUE);
82+
assertThat(source.getLocation()).isEqualTo("vendor");
83+
assertThat(source.getMappings()).hasSize(1);
84+
assertThat(source.getMappings().get(0).getSourceKey()).isEqualTo("sampling_rate");
85+
assertThat(source.getMappings().get(0).getPolicyType()).isEqualTo("trace_sampling_rate_policy");
86+
}
87+
88+
@Test
89+
void readFromConfigPropertiesReadsYamlWhenYamlPathProvided() throws Exception {
90+
Path configPath = tempDir.resolve("policy-init.yaml");
91+
Files.write(configPath, minimalYamlConfig().getBytes(StandardCharsets.UTF_8));
92+
93+
PolicyInitConfig config = configFromPaths(configPath.toString(), null);
94+
95+
assertThat(config.getSources()).hasSize(1);
96+
PolicySourceConfig source = config.getSources().get(0);
97+
assertThat(source.getKind()).isEqualTo(SourceKind.OPAMP);
98+
assertThat(source.getFormat()).isEqualTo(SourceFormat.JSONKEYVALUE);
99+
assertThat(source.getMappings()).hasSize(1);
100+
}
101+
102+
@Test
103+
void readFromConfigPropertiesReturnsNullOnFileReadFailure() {
104+
Path missing = tempDir.resolve("missing-policy-init.json");
105+
106+
assertThat(configFromPaths(null, missing.toString())).isNull();
107+
}
108+
109+
@Test
110+
void readFromConfigPropertiesReturnsNullOnParseFailure() throws Exception {
111+
Path badJson = tempDir.resolve("bad-policy-init.json");
112+
Files.write(badJson, "{}".getBytes(StandardCharsets.UTF_8));
113+
114+
assertThat(configFromPaths(null, badJson.toString())).isNull();
115+
}
116+
117+
private static PolicyInitConfig configFromPaths(String yamlPath, String jsonPath) {
118+
ConfigProperties config = mock(ConfigProperties.class);
119+
when(config.getString(PolicyInitConfig.POLICY_INIT_CONFIG_PROPERTY_YAML)).thenReturn(yamlPath);
120+
when(config.getString(PolicyInitConfig.POLICY_INIT_CONFIG_PROPERTY_JSON)).thenReturn(jsonPath);
121+
return PolicyInitConfig.readFromConfigProperties(config);
122+
}
123+
124+
private static String minimalJsonConfig() {
125+
return "{\"sources\":[{\"kind\":\"opamp\",\"format\":\"jsonkeyvalue\",\"location\":\"vendor\","
126+
+ "\"mappings\":[{\"sourceKey\":\"sampling_rate\",\"policyType\":\"trace_sampling_rate_policy\"}]}]}";
127+
}
128+
129+
private static String jsonWithLocation(String location) {
130+
return "{\"sources\":[{\"kind\":\"opamp\",\"format\":\"jsonkeyvalue\",\"location\":\""
131+
+ location
132+
+ "\",\"mappings\":[{\"sourceKey\":\"sampling_rate\",\"policyType\":\"trace_sampling_rate_policy\"}]}]}";
133+
}
134+
135+
private static String minimalYamlConfig() {
136+
return "sources:\n"
137+
+ " - kind: opamp\n"
138+
+ " format: jsonkeyvalue\n"
139+
+ " location: vendor\n"
140+
+ " mappings:\n"
141+
+ " - sourceKey: sampling_rate\n"
142+
+ " policyType: trace_sampling_rate_policy\n";
143+
}
144+
145+
private static String yamlWithLocation(String location) {
146+
return "sources:\n"
147+
+ " - kind: opamp\n"
148+
+ " format: jsonkeyvalue\n"
149+
+ " location: "
150+
+ location
151+
+ "\n"
152+
+ " mappings:\n"
153+
+ " - sourceKey: sampling_rate\n"
154+
+ " policyType: trace_sampling_rate_policy\n";
155+
}
156+
}

0 commit comments

Comments
 (0)