Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
03578c6
copy v0.3.0 and update import definition
codeboten Sep 25, 2025
ba8730b
update AttributeNameValueType to AttributeType
codeboten Sep 25, 2025
b21f94b
update Zipkin to ZipkinSpanExporter
codeboten Sep 25, 2025
6c9e47c
rename LanguageSpecificInstrumentation -> ExperimentalLanguageSpecifi…
codeboten Sep 25, 2025
245cd8c
Prometheus -> ExperimentalPrometheusMetricExporter
codeboten Sep 25, 2025
1005fcb
Console -> ConsoleExporter
codeboten Sep 25, 2025
967e3c4
update OTLP exporter config
codeboten Sep 25, 2025
7f63de5
add testdata
codeboten Sep 25, 2025
c9611d9
update config
codeboten Sep 25, 2025
ca1e391
update signals
codeboten Sep 25, 2025
7d4de9a
update resource parsing
codeboten Oct 9, 2025
6192a42
incremental improvements
codeboten Oct 15, 2025
1840b0a
add 1.0.0-rc1 test file
codeboten Oct 15, 2025
45598a1
set defaults for disabled/log_level
codeboten Oct 15, 2025
625f805
add json parsing/tests
codeboten Oct 15, 2025
472e29b
refactor common logic
codeboten Oct 16, 2025
8ad1d98
add env parsing test
codeboten Oct 16, 2025
115b925
fix test
codeboten Oct 16, 2025
24718b1
fix license check
codeboten Oct 16, 2025
e252a4c
add changelog
codeboten Oct 16, 2025
4f8330f
move common code
codeboten Oct 16, 2025
63b3719
add validation tests for BatchLogRecordProcessor
codeboten Oct 16, 2025
3e75483
add validation tests for BatchSpanProcessor
codeboten Oct 16, 2025
2948c97
add validation/tests for CardinalityLimits
codeboten Oct 16, 2025
5bb32a3
add validation/tests for SpanLimits
codeboten Oct 16, 2025
f768493
these have been moved
codeboten Oct 21, 2025
9b5fc2c
remove dupe files, update test data to add detectors TODO
codeboten Oct 22, 2025
6237c08
remove createTLSConfig, reuse refactored code
codeboten Oct 23, 2025
64211b5
clean up
codeboten Oct 27, 2025
5e18781
test cleanup
codeboten Oct 28, 2025
49f9e77
remove dead code
codeboten Oct 28, 2025
91eda36
lint
codeboten Oct 29, 2025
c14fcc3
re-enable tests with NewSDK
codeboten Oct 31, 2025
8d05a12
clean up
codeboten Nov 6, 2025
2714a67
update tests
codeboten Nov 6, 2025
e10a1b2
Added Test for http.Handler returned from zpages.NewTracezHandler (#8…
sonalgaud12 Nov 6, 2025
577d0d2
Merge branch 'main' into codeboten/otelconf-v1.0.0-rc1
codeboten Nov 7, 2025
e5659f0
Merge branch 'main' into codeboten/otelconf-v1.0.0-rc1
codeboten Nov 10, 2025
666c1ee
Merge branch 'main' into codeboten/otelconf-v1.0.0-rc1
codeboten Nov 10, 2025
ae318e2
Merge branch 'main' into codeboten/otelconf-v1.0.0-rc1
codeboten Nov 12, 2025
d37bcf6
Merge branch 'main' into codeboten/otelconf-v1.0.0-rc1
codeboten Nov 12, 2025
d3c85a7
Merge branch 'main' into codeboten/otelconf-v1.0.0-rc1
codeboten Nov 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add unmarshaling and validation for `OTLPHttpExporter`, `OTLPGrpcExporter`, `OTLPGrpcMetricExporter` and `OTLPHttpMetricExporter` to v1.0.0 model in `go.opentelemetry.io/contrib/otelconf`. (#8112)
- Add a `WithSpanNameFormatter` option to `go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo`. (#7986)
- 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)
- 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)

### Changed

Expand Down
171 changes: 171 additions & 0 deletions otelconf/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

// Package otelconf provides an OpenTelemetry declarative configuration SDK.
package otelconf // import "go.opentelemetry.io/contrib/otelconf"

import (
"context"
"errors"

"go.opentelemetry.io/otel/log"
nooplog "go.opentelemetry.io/otel/log/noop"
"go.opentelemetry.io/otel/metric"
noopmetric "go.opentelemetry.io/otel/metric/noop"
sdklog "go.opentelemetry.io/otel/sdk/log"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
nooptrace "go.opentelemetry.io/otel/trace/noop"
yaml "go.yaml.in/yaml/v3"

"go.opentelemetry.io/contrib/otelconf/internal/provider"
)

// SDK is a struct that contains all the providers
// configured via the configuration model.
type SDK struct {
meterProvider metric.MeterProvider
tracerProvider trace.TracerProvider
loggerProvider log.LoggerProvider
shutdown shutdownFunc
}

// TracerProvider returns a configured trace.TracerProvider.
func (s *SDK) TracerProvider() trace.TracerProvider {
return s.tracerProvider
}

// MeterProvider returns a configured metric.MeterProvider.
func (s *SDK) MeterProvider() metric.MeterProvider {
return s.meterProvider
}

// LoggerProvider returns a configured log.LoggerProvider.
func (s *SDK) LoggerProvider() log.LoggerProvider {
return s.loggerProvider
}

// Shutdown calls shutdown on all configured providers.
func (s *SDK) Shutdown(ctx context.Context) error {
return s.shutdown(ctx)
}

var noopSDK = SDK{
loggerProvider: nooplog.LoggerProvider{},
meterProvider: noopmetric.MeterProvider{},
tracerProvider: nooptrace.TracerProvider{},
shutdown: func(context.Context) error { return nil },
}

// NewSDK creates SDK providers based on the configuration model.
func NewSDK(opts ...ConfigurationOption) (SDK, error) {
o := configOptions{
ctx: context.Background(),
}
for _, opt := range opts {
o = opt.apply(o)
}
if o.opentelemetryConfig.Disabled != nil && *o.opentelemetryConfig.Disabled {
return noopSDK, nil
}

r, err := newResource(o.opentelemetryConfig.Resource)
if err != nil {
return noopSDK, err
}

mp, mpShutdown, err := meterProvider(o, r)
if err != nil {
return noopSDK, err
}

tp, tpShutdown, err := tracerProvider(o, r)
if err != nil {
return noopSDK, err
}

lp, lpShutdown, err := loggerProvider(o, r)
if err != nil {
return noopSDK, err
}

return SDK{
meterProvider: mp,
tracerProvider: tp,
loggerProvider: lp,
shutdown: func(ctx context.Context) error {
return errors.Join(mpShutdown(ctx), tpShutdown(ctx), lpShutdown(ctx))
},
}, nil
}

// ConfigurationOption configures options for providers.
type ConfigurationOption interface {
apply(configOptions) configOptions
}

type configurationOptionFunc func(configOptions) configOptions

func (fn configurationOptionFunc) apply(cfg configOptions) configOptions {
return fn(cfg)
}

// WithContext sets the context.Context for the SDK.
func WithContext(ctx context.Context) ConfigurationOption {
return configurationOptionFunc(func(c configOptions) configOptions {
c.ctx = ctx
return c
})
}

// WithOpenTelemetryConfiguration sets the OpenTelemetryConfiguration used
// to produce the SDK.
func WithOpenTelemetryConfiguration(cfg OpenTelemetryConfiguration) ConfigurationOption {
return configurationOptionFunc(func(c configOptions) configOptions {
c.opentelemetryConfig = cfg
return c
})
}

// WithLoggerProviderOptions appends LoggerProviderOptions used for constructing
// the LoggerProvider. OpenTelemetryConfiguration takes precedence over these options.
func WithLoggerProviderOptions(opts ...sdklog.LoggerProviderOption) ConfigurationOption {
return configurationOptionFunc(func(c configOptions) configOptions {
c.loggerProviderOptions = append(c.loggerProviderOptions, opts...)
return c
})
}

// WithMeterProviderOptions appends metric.Options used for constructing the
// MeterProvider. OpenTelemetryConfiguration takes precedence over these options.
func WithMeterProviderOptions(opts ...sdkmetric.Option) ConfigurationOption {
return configurationOptionFunc(func(c configOptions) configOptions {
c.meterProviderOptions = append(c.meterProviderOptions, opts...)
return c
})
}

// WithTracerProviderOptions appends TracerProviderOptions used for constructing
// the TracerProvider. OpenTelemetryConfiguration takes precedence over these options.
func WithTracerProviderOptions(opts ...sdktrace.TracerProviderOption) ConfigurationOption {
return configurationOptionFunc(func(c configOptions) configOptions {
c.tracerProviderOptions = append(c.tracerProviderOptions, opts...)
return c
})
}

// ParseYAML parses a YAML configuration file into an OpenTelemetryConfiguration.
func ParseYAML(file []byte) (*OpenTelemetryConfiguration, error) {
file, err := provider.ReplaceEnvVars(file)
if err != nil {
return nil, err
}
var cfg OpenTelemetryConfiguration
err = yaml.Unmarshal(file, &cfg)
if err != nil {
return nil, err
}

return &cfg, nil
}
26 changes: 25 additions & 1 deletion otelconf/config_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ var enumValuesOTLPMetricDefaultHistogramAggregation = []any{
type configOptions struct {
ctx context.Context
opentelemetryConfig OpenTelemetryConfiguration
meterProviderOptions []sdkmetric.Option
loggerProviderOptions []sdklog.LoggerProviderOption
meterProviderOptions []sdkmetric.Option
tracerProviderOptions []sdktrace.TracerProviderOption
}

Expand Down Expand Up @@ -155,6 +155,30 @@ func newErrInvalid(id string) error {
return &errInvalid{Identifier: id}
}

// unmarshalSamplerTypes handles always_on and always_off sampler unmarshaling.
func unmarshalSamplerTypes(raw map[string]any, plain *Sampler) {
// always_on can be nil, must check and set here
if _, ok := raw["always_on"]; ok {
plain.AlwaysOn = AlwaysOnSampler{}
}
// always_off can be nil, must check and set here
if _, ok := raw["always_off"]; ok {
plain.AlwaysOff = AlwaysOffSampler{}
}
}

// unmarshalMetricProducer handles opencensus metric producer unmarshaling.
func unmarshalMetricProducer(raw map[string]any, plain *MetricProducer) {
// opencensus can be nil, must check and set here
if v, ok := raw["opencensus"]; ok && v == nil {
delete(raw, "opencensus")
plain.Opencensus = OpenCensusMetricProducer{}
}
if len(raw) > 0 {
plain.AdditionalProperties = raw
}
}

// validatePeriodicMetricReader handles validation for PeriodicMetricReader.
func validatePeriodicMetricReader(plain *PeriodicMetricReader) error {
if plain.Timeout != nil && 0 > *plain.Timeout {
Expand Down
147 changes: 143 additions & 4 deletions otelconf/config_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,7 @@ func (j *BatchLogRecordProcessor) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(sh.Exporter, &sh.Plain.Exporter); err != nil {
return err
}
err := validateBatchLogRecordProcessor((*BatchLogRecordProcessor)(&sh.Plain))
if err != nil {
if err := validateBatchLogRecordProcessor((*BatchLogRecordProcessor)(&sh.Plain)); err != nil {
return err
}
*j = BatchLogRecordProcessor(sh.Plain)
Expand All @@ -307,14 +306,122 @@ func (j *BatchSpanProcessor) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(sh.Exporter, &sh.Plain.Exporter); err != nil {
return err
}
err := validateBatchSpanProcessor((*BatchSpanProcessor)(&sh.Plain))
if err != nil {
if err := validateBatchSpanProcessor((*BatchSpanProcessor)(&sh.Plain)); err != nil {
return err
}
*j = BatchSpanProcessor(sh.Plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *OpenTelemetryConfiguration) UnmarshalJSON(b []byte) error {
type Plain OpenTelemetryConfiguration
type shadow struct {
Plain
FileFormat json.RawMessage `json:"file_format"`
LoggerProvider json.RawMessage `json:"logger_provider"`
MeterProvider json.RawMessage `json:"meter_provider"`
TracerProvider json.RawMessage `json:"tracer_provider"`
Propagator json.RawMessage `json:"propagator"`
Resource json.RawMessage `json:"resource"`
InstrumentationDevelopment json.RawMessage `json:"instrumentation/development"`
AttributeLimits json.RawMessage `json:"attribute_limits"`
Disabled json.RawMessage `json:"disabled"`
LogLevel json.RawMessage `json:"log_level"`
}
var sh shadow
if err := json.Unmarshal(b, &sh); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}

if len(sh.FileFormat) == 0 {
return newErrRequired(j, "file_format")
}

if err := json.Unmarshal(sh.FileFormat, &sh.Plain.FileFormat); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}

if sh.LoggerProvider != nil {
var l LoggerProviderJson
if err := json.Unmarshal(sh.LoggerProvider, &l); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
sh.Plain.LoggerProvider = &l
}

if sh.MeterProvider != nil {
var m MeterProviderJson
if err := json.Unmarshal(sh.MeterProvider, &m); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
sh.Plain.MeterProvider = &m
}

if sh.TracerProvider != nil {
var t TracerProviderJson
if err := json.Unmarshal(sh.TracerProvider, &t); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
sh.Plain.TracerProvider = &t
}

if sh.Propagator != nil {
var p PropagatorJson
if err := json.Unmarshal(sh.Propagator, &p); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
sh.Plain.Propagator = &p
}

if sh.Resource != nil {
var r ResourceJson
if err := json.Unmarshal(sh.Resource, &r); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
sh.Plain.Resource = &r
}

if sh.InstrumentationDevelopment != nil {
var r InstrumentationJson
if err := json.Unmarshal(sh.InstrumentationDevelopment, &r); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
sh.Plain.InstrumentationDevelopment = &r
}

if sh.AttributeLimits != nil {
var r AttributeLimits
if err := json.Unmarshal(sh.AttributeLimits, &r); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
sh.Plain.AttributeLimits = &r
}

if sh.Disabled != nil {
if err := json.Unmarshal(sh.Disabled, &sh.Plain.Disabled); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
} else {
// Configure if the SDK is disabled or not.
// If omitted or null, false is used.
sh.Plain.Disabled = ptr(false)
}

if sh.LogLevel != nil {
if err := json.Unmarshal(sh.LogLevel, &sh.Plain.LogLevel); err != nil {
return errors.Join(newErrUnmarshal(j), err)
}
} else {
// Configure the log level of the internal logger used by the SDK.
// If omitted, info is used.
sh.Plain.LogLevel = ptr("info")
}

*j = OpenTelemetryConfiguration(sh.Plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *PeriodicMetricReader) UnmarshalJSON(b []byte) error {
type Plain PeriodicMetricReader
Expand Down Expand Up @@ -714,3 +821,35 @@ func (j *PullMetricReader) UnmarshalJSON(b []byte) error {
*j = PullMetricReader(sh.Plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *Sampler) UnmarshalJSON(b []byte) error {
var raw map[string]any
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
type Plain Sampler
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
unmarshalSamplerTypes(raw, (*Sampler)(&plain))
*j = Sampler(plain)
return nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *MetricProducer) UnmarshalJSON(b []byte) error {
var raw map[string]any
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
type Plain MetricProducer
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
unmarshalMetricProducer(raw, (*MetricProducer)(&plain))
*j = MetricProducer(plain)
return nil
}
Loading
Loading