Skip to content

Commit 76c48fd

Browse files
codebotensonalgaud12dmathieuXSAM
authored
otelconf: add support for 1.0.0 release candidate (#8026)
Signed-off-by: alex boten <[email protected]> Co-authored-by: Sonal Gaud <[email protected]> Co-authored-by: Damien Mathieu <[email protected]> Co-authored-by: Sam Xie <[email protected]>
1 parent 9524af6 commit 76c48fd

17 files changed

+1469
-101
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2020
- Add unmarshaling and validation for `OTLPHttpExporter`, `OTLPGrpcExporter`, `OTLPGrpcMetricExporter` and `OTLPHttpMetricExporter` to v1.0.0 model in `go.opentelemetry.io/contrib/otelconf`. (#8112)
2121
- Add a `WithSpanNameFormatter` option to `go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo`. (#7986)
2222
- Add unmarshaling and validation for `AttributeType`, `AttributeNameValue`, `SimpleSpanProcessor`, `SimpleLogRecordProcessor`, `ZipkinSpanExporter`, `NameStringValuePair`, `InstrumentType`, `ExperimentalPeerInstrumentationServiceMappingElem`, `ExporterDefaultHistogramAggregation`, `PullMetricReader` to v1.0.0 model in `go.opentelemetry.io/contrib/otelconf`. (#8127)
23+
- Updated `go.opentelemetry.io/contrib/otelconf` to include the [v1.0.0-rc2](https://github.com/open-telemetry/opentelemetry-configuration/releases/tag/v1.0.0-rc.2) release candidate of schema which includes backwards incompatible changes. (#8026)
2324

2425
### Changed
2526

otelconf/config.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Package otelconf provides an OpenTelemetry declarative configuration SDK.
5+
package otelconf // import "go.opentelemetry.io/contrib/otelconf"
6+
7+
import (
8+
"context"
9+
"errors"
10+
11+
"go.opentelemetry.io/otel/log"
12+
nooplog "go.opentelemetry.io/otel/log/noop"
13+
"go.opentelemetry.io/otel/metric"
14+
noopmetric "go.opentelemetry.io/otel/metric/noop"
15+
sdklog "go.opentelemetry.io/otel/sdk/log"
16+
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
17+
sdktrace "go.opentelemetry.io/otel/sdk/trace"
18+
"go.opentelemetry.io/otel/trace"
19+
nooptrace "go.opentelemetry.io/otel/trace/noop"
20+
yaml "go.yaml.in/yaml/v3"
21+
22+
"go.opentelemetry.io/contrib/otelconf/internal/provider"
23+
)
24+
25+
// SDK is a struct that contains all the providers
26+
// configured via the configuration model.
27+
type SDK struct {
28+
meterProvider metric.MeterProvider
29+
tracerProvider trace.TracerProvider
30+
loggerProvider log.LoggerProvider
31+
shutdown shutdownFunc
32+
}
33+
34+
// TracerProvider returns a configured trace.TracerProvider.
35+
func (s *SDK) TracerProvider() trace.TracerProvider {
36+
return s.tracerProvider
37+
}
38+
39+
// MeterProvider returns a configured metric.MeterProvider.
40+
func (s *SDK) MeterProvider() metric.MeterProvider {
41+
return s.meterProvider
42+
}
43+
44+
// LoggerProvider returns a configured log.LoggerProvider.
45+
func (s *SDK) LoggerProvider() log.LoggerProvider {
46+
return s.loggerProvider
47+
}
48+
49+
// Shutdown calls shutdown on all configured providers.
50+
func (s *SDK) Shutdown(ctx context.Context) error {
51+
return s.shutdown(ctx)
52+
}
53+
54+
var noopSDK = SDK{
55+
loggerProvider: nooplog.LoggerProvider{},
56+
meterProvider: noopmetric.MeterProvider{},
57+
tracerProvider: nooptrace.TracerProvider{},
58+
shutdown: func(context.Context) error { return nil },
59+
}
60+
61+
// NewSDK creates SDK providers based on the configuration model.
62+
func NewSDK(opts ...ConfigurationOption) (SDK, error) {
63+
o := configOptions{
64+
ctx: context.Background(),
65+
}
66+
for _, opt := range opts {
67+
o = opt.apply(o)
68+
}
69+
if o.opentelemetryConfig.Disabled != nil && *o.opentelemetryConfig.Disabled {
70+
return noopSDK, nil
71+
}
72+
73+
r, err := newResource(o.opentelemetryConfig.Resource)
74+
if err != nil {
75+
return noopSDK, err
76+
}
77+
78+
mp, mpShutdown, err := meterProvider(o, r)
79+
if err != nil {
80+
return noopSDK, err
81+
}
82+
83+
tp, tpShutdown, err := tracerProvider(o, r)
84+
if err != nil {
85+
return noopSDK, err
86+
}
87+
88+
lp, lpShutdown, err := loggerProvider(o, r)
89+
if err != nil {
90+
return noopSDK, err
91+
}
92+
93+
return SDK{
94+
meterProvider: mp,
95+
tracerProvider: tp,
96+
loggerProvider: lp,
97+
shutdown: func(ctx context.Context) error {
98+
return errors.Join(mpShutdown(ctx), tpShutdown(ctx), lpShutdown(ctx))
99+
},
100+
}, nil
101+
}
102+
103+
// ConfigurationOption configures options for providers.
104+
type ConfigurationOption interface {
105+
apply(configOptions) configOptions
106+
}
107+
108+
type configurationOptionFunc func(configOptions) configOptions
109+
110+
func (fn configurationOptionFunc) apply(cfg configOptions) configOptions {
111+
return fn(cfg)
112+
}
113+
114+
// WithContext sets the context.Context for the SDK.
115+
func WithContext(ctx context.Context) ConfigurationOption {
116+
return configurationOptionFunc(func(c configOptions) configOptions {
117+
c.ctx = ctx
118+
return c
119+
})
120+
}
121+
122+
// WithOpenTelemetryConfiguration sets the OpenTelemetryConfiguration used
123+
// to produce the SDK.
124+
func WithOpenTelemetryConfiguration(cfg OpenTelemetryConfiguration) ConfigurationOption {
125+
return configurationOptionFunc(func(c configOptions) configOptions {
126+
c.opentelemetryConfig = cfg
127+
return c
128+
})
129+
}
130+
131+
// WithLoggerProviderOptions appends LoggerProviderOptions used for constructing
132+
// the LoggerProvider. OpenTelemetryConfiguration takes precedence over these options.
133+
func WithLoggerProviderOptions(opts ...sdklog.LoggerProviderOption) ConfigurationOption {
134+
return configurationOptionFunc(func(c configOptions) configOptions {
135+
c.loggerProviderOptions = append(c.loggerProviderOptions, opts...)
136+
return c
137+
})
138+
}
139+
140+
// WithMeterProviderOptions appends metric.Options used for constructing the
141+
// MeterProvider. OpenTelemetryConfiguration takes precedence over these options.
142+
func WithMeterProviderOptions(opts ...sdkmetric.Option) ConfigurationOption {
143+
return configurationOptionFunc(func(c configOptions) configOptions {
144+
c.meterProviderOptions = append(c.meterProviderOptions, opts...)
145+
return c
146+
})
147+
}
148+
149+
// WithTracerProviderOptions appends TracerProviderOptions used for constructing
150+
// the TracerProvider. OpenTelemetryConfiguration takes precedence over these options.
151+
func WithTracerProviderOptions(opts ...sdktrace.TracerProviderOption) ConfigurationOption {
152+
return configurationOptionFunc(func(c configOptions) configOptions {
153+
c.tracerProviderOptions = append(c.tracerProviderOptions, opts...)
154+
return c
155+
})
156+
}
157+
158+
// ParseYAML parses a YAML configuration file into an OpenTelemetryConfiguration.
159+
func ParseYAML(file []byte) (*OpenTelemetryConfiguration, error) {
160+
file, err := provider.ReplaceEnvVars(file)
161+
if err != nil {
162+
return nil, err
163+
}
164+
var cfg OpenTelemetryConfiguration
165+
err = yaml.Unmarshal(file, &cfg)
166+
if err != nil {
167+
return nil, err
168+
}
169+
170+
return &cfg, nil
171+
}

otelconf/config_common.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ var enumValuesOTLPMetricDefaultHistogramAggregation = []any{
5050
type configOptions struct {
5151
ctx context.Context
5252
opentelemetryConfig OpenTelemetryConfiguration
53-
meterProviderOptions []sdkmetric.Option
5453
loggerProviderOptions []sdklog.LoggerProviderOption
54+
meterProviderOptions []sdkmetric.Option
5555
tracerProviderOptions []sdktrace.TracerProviderOption
5656
}
5757

@@ -155,6 +155,30 @@ func newErrInvalid(id string) error {
155155
return &errInvalid{Identifier: id}
156156
}
157157

158+
// unmarshalSamplerTypes handles always_on and always_off sampler unmarshaling.
159+
func unmarshalSamplerTypes(raw map[string]any, plain *Sampler) {
160+
// always_on can be nil, must check and set here
161+
if _, ok := raw["always_on"]; ok {
162+
plain.AlwaysOn = AlwaysOnSampler{}
163+
}
164+
// always_off can be nil, must check and set here
165+
if _, ok := raw["always_off"]; ok {
166+
plain.AlwaysOff = AlwaysOffSampler{}
167+
}
168+
}
169+
170+
// unmarshalMetricProducer handles opencensus metric producer unmarshaling.
171+
func unmarshalMetricProducer(raw map[string]any, plain *MetricProducer) {
172+
// opencensus can be nil, must check and set here
173+
if v, ok := raw["opencensus"]; ok && v == nil {
174+
delete(raw, "opencensus")
175+
plain.Opencensus = OpenCensusMetricProducer{}
176+
}
177+
if len(raw) > 0 {
178+
plain.AdditionalProperties = raw
179+
}
180+
}
181+
158182
// validatePeriodicMetricReader handles validation for PeriodicMetricReader.
159183
func validatePeriodicMetricReader(plain *PeriodicMetricReader) error {
160184
if plain.Timeout != nil && 0 > *plain.Timeout {

otelconf/config_json.go

Lines changed: 143 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,7 @@ func (j *BatchLogRecordProcessor) UnmarshalJSON(b []byte) error {
281281
if err := json.Unmarshal(sh.Exporter, &sh.Plain.Exporter); err != nil {
282282
return err
283283
}
284-
err := validateBatchLogRecordProcessor((*BatchLogRecordProcessor)(&sh.Plain))
285-
if err != nil {
284+
if err := validateBatchLogRecordProcessor((*BatchLogRecordProcessor)(&sh.Plain)); err != nil {
286285
return err
287286
}
288287
*j = BatchLogRecordProcessor(sh.Plain)
@@ -307,14 +306,122 @@ func (j *BatchSpanProcessor) UnmarshalJSON(b []byte) error {
307306
if err := json.Unmarshal(sh.Exporter, &sh.Plain.Exporter); err != nil {
308307
return err
309308
}
310-
err := validateBatchSpanProcessor((*BatchSpanProcessor)(&sh.Plain))
311-
if err != nil {
309+
if err := validateBatchSpanProcessor((*BatchSpanProcessor)(&sh.Plain)); err != nil {
312310
return err
313311
}
314312
*j = BatchSpanProcessor(sh.Plain)
315313
return nil
316314
}
317315

316+
// UnmarshalJSON implements json.Unmarshaler.
317+
func (j *OpenTelemetryConfiguration) UnmarshalJSON(b []byte) error {
318+
type Plain OpenTelemetryConfiguration
319+
type shadow struct {
320+
Plain
321+
FileFormat json.RawMessage `json:"file_format"`
322+
LoggerProvider json.RawMessage `json:"logger_provider"`
323+
MeterProvider json.RawMessage `json:"meter_provider"`
324+
TracerProvider json.RawMessage `json:"tracer_provider"`
325+
Propagator json.RawMessage `json:"propagator"`
326+
Resource json.RawMessage `json:"resource"`
327+
InstrumentationDevelopment json.RawMessage `json:"instrumentation/development"`
328+
AttributeLimits json.RawMessage `json:"attribute_limits"`
329+
Disabled json.RawMessage `json:"disabled"`
330+
LogLevel json.RawMessage `json:"log_level"`
331+
}
332+
var sh shadow
333+
if err := json.Unmarshal(b, &sh); err != nil {
334+
return errors.Join(newErrUnmarshal(j), err)
335+
}
336+
337+
if len(sh.FileFormat) == 0 {
338+
return newErrRequired(j, "file_format")
339+
}
340+
341+
if err := json.Unmarshal(sh.FileFormat, &sh.Plain.FileFormat); err != nil {
342+
return errors.Join(newErrUnmarshal(j), err)
343+
}
344+
345+
if sh.LoggerProvider != nil {
346+
var l LoggerProviderJson
347+
if err := json.Unmarshal(sh.LoggerProvider, &l); err != nil {
348+
return errors.Join(newErrUnmarshal(j), err)
349+
}
350+
sh.Plain.LoggerProvider = &l
351+
}
352+
353+
if sh.MeterProvider != nil {
354+
var m MeterProviderJson
355+
if err := json.Unmarshal(sh.MeterProvider, &m); err != nil {
356+
return errors.Join(newErrUnmarshal(j), err)
357+
}
358+
sh.Plain.MeterProvider = &m
359+
}
360+
361+
if sh.TracerProvider != nil {
362+
var t TracerProviderJson
363+
if err := json.Unmarshal(sh.TracerProvider, &t); err != nil {
364+
return errors.Join(newErrUnmarshal(j), err)
365+
}
366+
sh.Plain.TracerProvider = &t
367+
}
368+
369+
if sh.Propagator != nil {
370+
var p PropagatorJson
371+
if err := json.Unmarshal(sh.Propagator, &p); err != nil {
372+
return errors.Join(newErrUnmarshal(j), err)
373+
}
374+
sh.Plain.Propagator = &p
375+
}
376+
377+
if sh.Resource != nil {
378+
var r ResourceJson
379+
if err := json.Unmarshal(sh.Resource, &r); err != nil {
380+
return errors.Join(newErrUnmarshal(j), err)
381+
}
382+
sh.Plain.Resource = &r
383+
}
384+
385+
if sh.InstrumentationDevelopment != nil {
386+
var r InstrumentationJson
387+
if err := json.Unmarshal(sh.InstrumentationDevelopment, &r); err != nil {
388+
return errors.Join(newErrUnmarshal(j), err)
389+
}
390+
sh.Plain.InstrumentationDevelopment = &r
391+
}
392+
393+
if sh.AttributeLimits != nil {
394+
var r AttributeLimits
395+
if err := json.Unmarshal(sh.AttributeLimits, &r); err != nil {
396+
return errors.Join(newErrUnmarshal(j), err)
397+
}
398+
sh.Plain.AttributeLimits = &r
399+
}
400+
401+
if sh.Disabled != nil {
402+
if err := json.Unmarshal(sh.Disabled, &sh.Plain.Disabled); err != nil {
403+
return errors.Join(newErrUnmarshal(j), err)
404+
}
405+
} else {
406+
// Configure if the SDK is disabled or not.
407+
// If omitted or null, false is used.
408+
sh.Plain.Disabled = ptr(false)
409+
}
410+
411+
if sh.LogLevel != nil {
412+
if err := json.Unmarshal(sh.LogLevel, &sh.Plain.LogLevel); err != nil {
413+
return errors.Join(newErrUnmarshal(j), err)
414+
}
415+
} else {
416+
// Configure the log level of the internal logger used by the SDK.
417+
// If omitted, info is used.
418+
sh.Plain.LogLevel = ptr("info")
419+
}
420+
421+
*j = OpenTelemetryConfiguration(sh.Plain)
422+
return nil
423+
}
424+
318425
// UnmarshalJSON implements json.Unmarshaler.
319426
func (j *PeriodicMetricReader) UnmarshalJSON(b []byte) error {
320427
type Plain PeriodicMetricReader
@@ -714,3 +821,35 @@ func (j *PullMetricReader) UnmarshalJSON(b []byte) error {
714821
*j = PullMetricReader(sh.Plain)
715822
return nil
716823
}
824+
825+
// UnmarshalJSON implements json.Unmarshaler.
826+
func (j *Sampler) UnmarshalJSON(b []byte) error {
827+
var raw map[string]any
828+
if err := json.Unmarshal(b, &raw); err != nil {
829+
return err
830+
}
831+
type Plain Sampler
832+
var plain Plain
833+
if err := json.Unmarshal(b, &plain); err != nil {
834+
return err
835+
}
836+
unmarshalSamplerTypes(raw, (*Sampler)(&plain))
837+
*j = Sampler(plain)
838+
return nil
839+
}
840+
841+
// UnmarshalJSON implements json.Unmarshaler.
842+
func (j *MetricProducer) UnmarshalJSON(b []byte) error {
843+
var raw map[string]any
844+
if err := json.Unmarshal(b, &raw); err != nil {
845+
return err
846+
}
847+
type Plain MetricProducer
848+
var plain Plain
849+
if err := json.Unmarshal(b, &plain); err != nil {
850+
return err
851+
}
852+
unmarshalMetricProducer(raw, (*MetricProducer)(&plain))
853+
*j = MetricProducer(plain)
854+
return nil
855+
}

0 commit comments

Comments
 (0)