-
Notifications
You must be signed in to change notification settings - Fork 847
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Define dedicated file configuration SPI ComponentProvider #6457
Conversation
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change | ||
* at any time. | ||
*/ | ||
public class PrometheusComponentProvider implements ComponentProvider<MetricReader> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A demonstration ComponentProvider. Notice how config properties are accessed without dot notation since the YAML node is presented directly as the StructuredConfigProperties
.
* @throws ConfigurationException if the property is not a sequence of mappings | ||
*/ | ||
@Nullable | ||
List<StructuredConfigProperties> getStructuredList(String name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getStructured
and getStructuredList
are the key bits which allow reading complex data.
* @see #getConfig() | ||
*/ | ||
@Nullable | ||
abstract StructuredConfigProperties getStructuredConfig(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new method allows callers to determine if autoconfiguration was driven by file configuration or by env vars / system properties. Either this or getConfig
will return null. The other will be non-null.
If file configuration is used, getStructuredConfig
represents the full YAML config file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kinda the only unfortunate downside of this approach that I can find thus far. It's a small drag that users of the autoconfigured sdk now have to be aware or otherwise check which config was used to get the data they need.
It feels like there is room to flatten the structured config into ConfigProperties
and also to objectify the ConfigProperties
into a structured thing...but we can have that conversation another time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a small drag that users of the autoconfigured sdk now have to be aware or otherwise check which config was used to get the data they need.
I would characterize it slightly differently: Providers of custom components like exporters and samplers need to be aware that somebody can use file based config or flat system property / env var based config, and provide different SPI implementations for each. This is frustrating, but seems to be the inevitable result of otel getting as far as it did without a proper configuration story. As I mentioned in the PR description, I started with the opposite approach and tried to have a single unified ConfigProperties
for both configuration routes. I've concluded while this is simpler from an API standpoint, its more confusing and brittle for users, since even though we can do some gymnastics to make ConfigProperties
work for both cases, the data presented to SPI implementers will be different (i.e. the property names and structure and semantics will be different for flat env vars than in structured config). So there appears to be no getting around confronting the user with this difference. Might as well make it as explicit and obvious as possible.
assertThat(otherProps.getString("str_key")).isEqualTo("str_value"); | ||
StructuredConfigProperties otherMapKeyProps = otherProps.getStructured("map_key"); | ||
assertThat(otherMapKeyProps).isNotNull(); | ||
assertThat(otherMapKeyProps.getString("str_key1")).isEqualTo("str_value1"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test demonstrates how a consumers like the otel java agent could access complex config data which is not part of the core file configuration schema. The other
key and the structure it encloses is not part of the core schema yet its contents are accessible.
This will be important for configuring java agent specific options, like content for the JMX integration.
MetricReader metricReader = | ||
FileConfigUtil.loadComponent( | ||
spiHelper, MetricReader.class, "prometheus", prometheusModel); | ||
return FileConfigUtil.addAndReturn(closeables, metricReader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what it looks like to load a component in the file configuration implementation. We state that we want ComponentProvider
which provides instances of MetricReader.class
named prometheus
, and we pass the prometheusModel
to it (which is translated to StructuredConfigProperties).
Nice and easy.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6457 +/- ##
============================================
- Coverage 90.86% 90.72% -0.14%
- Complexity 6155 6214 +59
============================================
Files 675 678 +3
Lines 18461 18621 +160
Branches 1813 1828 +15
============================================
+ Hits 16774 16894 +120
- Misses 1151 1180 +29
- Partials 536 547 +11 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jack-berg this is a fantastic step forward on the config front!
...ure-spi/src/main/java/io/opentelemetry/sdk/autoconfigure/spi/internal/ComponentProvider.java
Show resolved
Hide resolved
...rc/main/java/io/opentelemetry/sdk/autoconfigure/spi/internal/StructuredConfigProperties.java
Outdated
Show resolved
Hide resolved
...java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlStructuredConfigProperties.java
Outdated
Show resolved
Hide resolved
...java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlStructuredConfigProperties.java
Show resolved
Hide resolved
* @see #getConfig() | ||
*/ | ||
@Nullable | ||
abstract StructuredConfigProperties getStructuredConfig(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kinda the only unfortunate downside of this approach that I can find thus far. It's a small drag that users of the autoconfigured sdk now have to be aware or otherwise check which config was used to get the data they need.
It feels like there is room to flatten the structured config into ConfigProperties
and also to objectify the ConfigProperties
into a structured thing...but we can have that conversation another time.
...ubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java
Show resolved
Hide resolved
@breedx-splk I would greatly appreciate another look when you have a chance 🙂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@open-telemetry/java-approvers will merge tomorrow if there are no additional comments. |
…y-java into component-provider
A while ago I opened PR #5912, which introduced ExtendedConfigProperties. The idea was to have an extended version of the ConfigProperties interface which included new accessors for reading structured data in addition to the simple types already exposed by ConfigProperties. Then, when file configuration needed to load a custom SDK extension component like SpanExporter, it would construct a ExtendedConfigProperties from the YAML contents and pass it to the SPI (i.e. ConfigurableSpanExporterProvider.
This approach is problematic because it requires SPI implementations to understand whether they're working on a file configuration context or not based on whether the ConfigProperties is actually an instance of ExtendedConfigProperties. The shape of data and the access patterns is quite different for file configuration vs env var / system property based configuration, so this whole thing is error prone and rather confusing.
In this PR, I propose a different direction which embraces the spec decision that file configuration should be thought of as the v2 of configuration, rather than something that is an extension of the existing env var / system property mechanism. Here's how I'm thinking about it:
otel.experimental.config.file
you're opting into this separate path. If you don't, all the existing SPIs and config mechanism works.ComponentProvider#create(StructuredConfigProperties)
.For demonstration purposes and to make this PR as simple as possible, I've implemented a single ComponentProvider in the
opentelemetry-exporters-prometheus
artifact. If this PR is merged, I will followup by implementing ComponentProvider for the other built in components.