[dynamic control] Add pipeline config initialization from declarative config or failover to file#2766
[dynamic control] Add pipeline config initialization from declarative config or failover to file#2766jackshirazi wants to merge 3 commits intoopen-telemetry:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds initialization of dynamic-control’s telemetry policy pipeline from OpenTelemetry declarative config (preferred) with fallback to file-based YAML/JSON config.
Changes:
- Add
PolicyInitConfigloaders for declarative config (telemetry_policy.sources) and declarative-first fallback helpers (including viaOpenTelemetry/ExtendedOpenTelemetry). - Add file-based loading from
otel.java.experimental.telemetry.policy.init.yaml/jsonwith YAML precedence and warning-on-failure behavior. - Add unit tests covering declarative vs file fallback selection and error cases.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/registry/PolicyInitConfig.java | Implements declarative-first init config parsing and file fallback, plus reflective access to “general config” accessor. |
| dynamic-control/src/test/java/io/opentelemetry/contrib/dynamic/policy/registry/PolicyInitConfigTest.java | Adds tests for YAML/JSON precedence, parse failures, and declarative-vs-file selection paths. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
dynamic-control/src/main/java/io/opentelemetry/contrib/dynamic/policy/registry/json/JsonNodePolicyInitConfigParser.java:55
- JSON init-config parsing now trims/normalizes optional
location, but other string fields (kind,format,sourceKey,policyType) are still accepted with leading/trailing whitespace (and even whitespace-only, sincerequireTextonly checksisEmpty()). This can lead to hard-to-debug mismatches because mapping keys/policy types are used verbatim downstream. Consider trimming and validating non-blank inrequireText(returning the trimmed value), and applying the same normalization to mapping fields for consistency with declarative parsing.
JsonNode locationNode = objectNode.get("location");
String location =
locationNode != null && locationNode.isTextual()
? normalizeOptionalText(locationNode.asText())
: null;
JsonNode mappingsNode =
requireArray(objectNode.get("mappings"), "Each source must define a 'mappings' array.");
List<PolicySourceMappingConfig> mappings = new ArrayList<>();
| } catch (NoSuchMethodException | ||
| | IllegalAccessException | ||
| | InvocationTargetException | ||
| | RuntimeException ignored) { | ||
| // Fall through to backwards-compatible accessor below. | ||
| } |
There was a problem hiding this comment.
should we scope this a bit more and add some logging? currently if the method exists but throws a NPE or something we'll fall through and the user might not know why
| } catch (NoSuchMethodException | |
| | IllegalAccessException | |
| | InvocationTargetException | |
| | RuntimeException ignored) { | |
| // Fall through to backwards-compatible accessor below. | |
| } | |
| } catch (NoSuchMethodException ignored) { | |
| // Method doesn't exist in this runtime version — fall through. | |
| } catch (IllegalAccessException | InvocationTargetException e) { | |
| logger.log(Level.WARNING, "Failed to invoke getGeneralConfig via reflection", e); | |
| } |
|
|
||
| List<DeclarativeConfigProperties> mappingConfigs = | ||
| sourceConfig.getStructuredList(MAPPINGS_DECLARATIVE_KEY); | ||
| if (mappingConfigs == null) { |
There was a problem hiding this comment.
should we also guard against empty maps?
| if (mappingConfigs == null) { | |
| if (mappingConfigs == null || mappingConfigs.isEmpty()) { |
| static final String TELEMETRY_POLICY_DECLARATIVE_KEY = "telemetry_policy"; | ||
| static final String SOURCES_DECLARATIVE_KEY = "sources"; | ||
| static final String KIND_DECLARATIVE_KEY = "kind"; | ||
| static final String FORMAT_DECLARATIVE_KEY = "format"; | ||
| static final String LOCATION_DECLARATIVE_KEY = "location"; | ||
| static final String MAPPINGS_DECLARATIVE_KEY = "mappings"; | ||
| static final String SOURCE_KEY_DECLARATIVE_KEY = "sourceKey"; | ||
| static final String POLICY_TYPE_DECLARATIVE_KEY = "policyType"; | ||
| static final String POLICY_INIT_CONFIG_PROPERTY_JSON = | ||
| "otel.java.experimental.telemetry.policy.init.json"; | ||
| static final String POLICY_INIT_CONFIG_PROPERTY_YAML = |
There was a problem hiding this comment.
any reason not to make these all private? I'm assuming ability to access them in tests but just checking
| } | ||
|
|
||
| @Nullable | ||
| static ConfigProvider getConfigProvider(@Nullable OpenTelemetry openTelemetry) { |
There was a problem hiding this comment.
| static ConfigProvider getConfigProvider(@Nullable OpenTelemetry openTelemetry) { | |
| private static ConfigProvider getConfigProvider(@Nullable OpenTelemetry openTelemetry) { |
Description:
Adding a method to read pipeline initialization from declarative config, or if not present failover to a file in yaml (or a json file).
The declarative config looks like
If declarative config is not present, the failover file is expected to have the node under
telemetry_policy, ie starting atsourcesas the top-level nodeExisting Issue(s):
#2546
Testing:
Added
Documentation:
Added
Outstanding items:
Wiring up the policy pipeline:
Steps needed for the wiring: