Skip to content

Commit

Permalink
Add support to configure views with config.NewSdk
Browse files Browse the repository at this point in the history
  • Loading branch information
bogdandrutu committed May 28, 2024
1 parent 1e8c7ca commit ed42741
Show file tree
Hide file tree
Showing 3 changed files with 593 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Added

- The `go.opentelemetry.io/contrib/config` add support to configure periodic reader interval and timeout. (#5661)
- Add support to configure views when creating MeterProvider using the config package. (#5654)

### Fixed

Expand Down
143 changes: 143 additions & 0 deletions config/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
otelprom "go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/noop"
"go.opentelemetry.io/otel/sdk/instrumentation"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
)
Expand All @@ -45,6 +47,15 @@ func meterProvider(cfg configOptions, res *resource.Resource) (metric.MeterProvi
errs = append(errs, err)
}
}
for _, vw := range cfg.opentelemetryConfig.MeterProvider.Views {
v, err := view(vw)
if err == nil {
opts = append(opts, sdkmetric.WithView(v))
} else {
errs = append(errs, err)

Check warning on line 55 in config/metric.go

View check run for this annotation

Codecov / codecov/patch

config/metric.go#L51-L55

Added lines #L51 - L55 were not covered by tests
}
}

if len(errs) > 0 {
return noop.NewMeterProvider(), noopShutdown, errors.Join(errs...)
}
Expand Down Expand Up @@ -266,3 +277,135 @@ func (rws readerWithServer) Shutdown(ctx context.Context) error {
rws.server.Shutdown(ctx),
)
}

func view(v View) (sdkmetric.View, error) {
if v.Selector == nil {
return nil, errors.New("view: no selector provided")
}

inst, err := instrument(*v.Selector)
if err != nil {
return nil, err
}

return sdkmetric.NewView(inst, stream(v.Stream)), nil
}

func instrument(vs ViewSelector) (sdkmetric.Instrument, error) {
kind, err := instrumentKind(vs.InstrumentType)
if err != nil {
return sdkmetric.Instrument{}, fmt.Errorf("view_selactor: %w", err)
}
return sdkmetric.Instrument{
Name: strOrEmpty(vs.InstrumentName),
Unit: strOrEmpty(vs.Unit),
Kind: kind,
Scope: instrumentation.Scope{
Name: strOrEmpty(vs.MeterName),
Version: strOrEmpty(vs.MeterVersion),
SchemaURL: strOrEmpty(vs.MeterSchemaUrl),
},
}, nil
}

func stream(vs *ViewStream) sdkmetric.Stream {
if vs == nil {
return sdkmetric.Stream{}
}

return sdkmetric.Stream{
Name: strOrEmpty(vs.Name),
Description: strOrEmpty(vs.Description),
AttributeFilter: attributeFilter(vs.AttributeKeys),
Aggregation: aggregation(vs.Aggregation),
}
}

func attributeFilter(attributeKeys []string) attribute.Filter {
var attrKeys []attribute.Key
for _, attrStr := range attributeKeys {
attrKeys = append(attrKeys, attribute.Key(attrStr))
}
return attribute.NewAllowKeysFilter(attrKeys...)
}

func aggregation(aggr *ViewStreamAggregation) sdkmetric.Aggregation {
if aggr == nil {
return nil
}

if aggr.Base2ExponentialBucketHistogram != nil {
return sdkmetric.AggregationBase2ExponentialHistogram{
MaxSize: int32(intOrZero(aggr.Base2ExponentialBucketHistogram.MaxSize)),
MaxScale: int32(intOrZero(aggr.Base2ExponentialBucketHistogram.MaxScale)),
// Need to negate because config has the positive action RecordMinMax.
NoMinMax: !boolOrFalse(aggr.Base2ExponentialBucketHistogram.RecordMinMax),
}
}
if aggr.Default != nil {
// TODO: Understand what to set here.
return nil
}
if aggr.Drop != nil {
return sdkmetric.AggregationDrop{}
}
if aggr.ExplicitBucketHistogram != nil {
return sdkmetric.AggregationExplicitBucketHistogram{
Boundaries: aggr.ExplicitBucketHistogram.Boundaries,
// Need to negate because config has the positive action RecordMinMax.
NoMinMax: !boolOrFalse(aggr.ExplicitBucketHistogram.RecordMinMax),
}
}
if aggr.LastValue != nil {
return sdkmetric.AggregationLastValue{}
}
if aggr.Sum != nil {
return sdkmetric.AggregationSum{}
}
return nil
}

func instrumentKind(vsit *ViewSelectorInstrumentType) (sdkmetric.InstrumentKind, error) {
if vsit == nil {
// Equivalent to instrumentKindUndefined.
return sdkmetric.InstrumentKind(0), nil
}

switch *vsit {
case ViewSelectorInstrumentTypeCounter:
return sdkmetric.InstrumentKindCounter, nil
case ViewSelectorInstrumentTypeUpDownCounter:
return sdkmetric.InstrumentKindUpDownCounter, nil
case ViewSelectorInstrumentTypeHistogram:
return sdkmetric.InstrumentKindHistogram, nil
case ViewSelectorInstrumentTypeObservableCounter:
return sdkmetric.InstrumentKindObservableCounter, nil
case ViewSelectorInstrumentTypeObservableUpDownCounter:
return sdkmetric.InstrumentKindObservableUpDownCounter, nil
case ViewSelectorInstrumentTypeObservableGauge:
return sdkmetric.InstrumentKindObservableGauge, nil
}

return sdkmetric.InstrumentKind(0), errors.New("instrument_type: invalid value")
}

func boolOrFalse(pBool *bool) bool {
if pBool == nil {
return false
}
return *pBool
}

func intOrZero(pInt *int) int {
if pInt == nil {
return 0
}
return *pInt
}

func strOrEmpty(pStr *string) string {
if pStr == nil {
return ""
}
return *pStr
}
Loading

0 comments on commit ed42741

Please sign in to comment.