opentelemetry-collector icon indicating copy to clipboard operation
opentelemetry-collector copied to clipboard

[otelcol] Obtain the Collector's effective configuration from `otelcol.Config`

Open evan-bradley opened this issue 1 year ago • 7 comments

Description

The current ConfmapProvider interface accurately reports the config provided to the Collector by the user, but fails to effectively report the Collector's effective configuration. In particular, it misses:

  • Default values for fields in Config structs.
  • Transformations done to Config structs by their Unmarshal or Validate methods.
  • Custom marshaling of types after we know the type of the config. This is most obvious with configopaque.String, where we want these values to always be redacted when sent out of the Collector.

As a result, I think we should attempt to get the Collector's effective configuration from otelcol.Config instead of using the map compiled by the confmap.Resolver. I initially intended to generate a confmap.Conf from otelcol.Config and call yaml.Marshal on that, but this encounters errors such as being unable to marshal Prometheus config which has invalid zero values. These errors don't occur when calling yaml.Marshal on otelcol.Config directly. I've updated and tested updating the ConfigWatcher interface to just accept an opaque any-typed data object and marshal that, and the end-to-end flow works. I haven't dug into this far enough to fully understand the differences between unmarshaling each type.

Two related PRs:

  • https://github.com/open-telemetry/opentelemetry-collector/pull/10137
  • https://github.com/open-telemetry/opentelemetry-collector/pull/10136

evan-bradley avatar May 10 '24 21:05 evan-bradley

To demonstrate the issue I'm seeing, this will fail:

cfg, _ := col.configProvider.Get(ctx, factories)
conf := confmap.New()
_ = conf.Marshal(cfg)
// This fails
bytes, err := yaml.Marshal(conf.ToStringMap())

This will succeed:

cfg, _ := col.configProvider.Get(ctx, factories)
// This succeeds
bytes, err := yaml.Marshal(cfg)

I'm fine just letting ConfigWatcher.NotifyConfig take an opaque any-typed parameter and telling the user to just marshal it with whatever format they want, but I don't fully understand why the first one fails. The second one also appears to make us more dependent on yaml since we don't have mapstructure as a buffer (e.g. we need to add yaml:"-" to confighttp.ClientConfig for the second snippet to work).

evan-bradley avatar May 10 '24 21:05 evan-bradley

As a result, I think we should attempt to get the Collector's effective configuration from otelcol.Config instead of using the map compiled by the confmap.Resolver. I initially intended to generate a confmap.Conf from otelcol.Config and call yaml.Marshal on that, but this encounters errors such as being unable to marshal Prometheus config which has invalid zero values. These errors don't occur when calling yaml.Marshal on otelcol.Config directly. I've updated and tested updating the ConfigWatcher interface to just accept an opaque any-typed data object and marshal that, and the end-to-end flow works. I haven't dug into this far enough to fully understand the differences between unmarshaling each type.

I think you should look into fixing marshal. /cc @atoulme

sfc-gh-bdrutu avatar May 12 '24 21:05 sfc-gh-bdrutu

I think you should look into fixing marshal.

Thanks for the tip, I think that's also the best path forward. I found that the issue is that we don't do anything with yaml tags, which is what most third-party structs annotate on their fields. I will issue a PR to find a solution to that problem then update this PR afterward.

evan-bradley avatar May 17 '24 13:05 evan-bradley

Codecov Report

Attention: Patch coverage is 33.33333% with 2 lines in your changes missing coverage. Please review.

Project coverage is 92.26%. Comparing base (08b0be7) to head (a708ac8). Report is 1 commits behind head on main.

Files Patch % Lines
otelcol/collector.go 33.33% 1 Missing and 1 partial :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #10139      +/-   ##
==========================================
- Coverage   92.35%   92.26%   -0.09%     
==========================================
  Files         395      395              
  Lines       18706    18703       -3     
==========================================
- Hits        17275    17257      -18     
- Misses       1070     1086      +16     
+ Partials      361      360       -1     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov[bot] avatar May 21 '24 18:05 codecov[bot]

I think you should look into fixing marshal.

Thanks for the tip, I think that's also the best path forward. I found that the issue is that we don't do anything with yaml tags, which is what most third-party structs annotate on their fields. I will issue a PR to find a solution to that problem then update this PR afterward.

I have a possible solution in https://github.com/open-telemetry/opentelemetry-collector/pull/10282.

Basically it adds a hook which looks for structs that have yaml tags but no mapstructure tags. For such structs, it uses the yaml package to "natively" convert the struct into map[string]any, which can then be marshaled by mapstructure in a generic way.

djaglowski avatar May 31 '24 17:05 djaglowski

This PR was marked stale due to lack of activity. It will be closed in 14 days.

github-actions[bot] avatar Jun 18 '24 03:06 github-actions[bot]

It seems like the ask to:

generate a confmap.Conf from otelcol.Config and call yaml.Marshal on that

cfg, _ := col.configProvider.Get(ctx, factories)
conf := confmap.New()
_ = conf.Marshal(cfg)
// This fails
bytes, err := yaml.Marshal(conf.ToStringMap())

is now supported following:

  • https://github.com/open-telemetry/opentelemetry-collector/pull/10310
  • https://github.com/open-telemetry/opentelemetry-collector/pull/10282

Are there any other scenarios where the code snippet above will fail ?

mackjmr avatar Jun 27 '24 15:06 mackjmr

@mackjmr You're right, this will work now; thanks for keeping an eye on it. I haven't been able to get back to this, but I have more time now and will push an update this week.

evan-bradley avatar Jul 01 '24 15:07 evan-bradley

is this purely internal change, or can the end user print the config now?

yurishkuro avatar Jul 12 '24 21:07 yurishkuro

This only affects the Collector APIs, but it is a step towards allowing the user to print the config.

evan-bradley avatar Jul 15 '24 15:07 evan-bradley