package meter import ( "context" "fmt" "os" "path/filepath" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) func WithServiceName(name string) func(*Option) error { return func(o *Option) error { o.serviceName = name return nil } } func WithAttributes(attrs ...attribute.KeyValue) func(context.Context, *Option) error { return func(_ context.Context, o *Option) error { o.attributes = attrs return nil } } func WithExtraResource(opts ...resource.Option) func(context.Context, *Option) error { return func(_ context.Context, o *Option) error { o.extraResource = opts return nil } } func WithReader(reader metric.Reader) func(context.Context, *Option) error { return func(_ context.Context, o *Option) error { o.reader = reader return nil } } type Option struct { reader metric.Reader serviceName string attributes []attribute.KeyValue extraResource []resource.Option } func newOptions(ctx context.Context, opts ...func(context.Context, *Option) error) (Option, error) { option := Option{ serviceName: filepath.Base(os.Args[0]), extraResource: []resource.Option{ resource.WithOS(), resource.WithProcess(), resource.WithContainer(), resource.WithHost(), }, } for idx, opt := range opts { if err := opt(ctx, &option); err != nil { return option, fmt.Errorf("option[%d]:%w", idx, err) } } return option, nil } func New(ctx context.Context, opts ...func(context.Context, *Option) error) (*metric.MeterProvider, error) { option, err := newOptions(ctx, opts...) if err != nil { return nil, fmt.Errorf("configure:%w", err) } extraResources, eerr := resource.New( ctx, append( option.extraResource, resource.WithAttributes( append( option.attributes, semconv.ServiceName(option.serviceName), )..., ), )..., ) if eerr != nil { return nil, fmt.Errorf("create extra resource: %w", eerr) } res, rerr := resource.Merge( resource.Default(), extraResources, ) if rerr != nil { return nil, fmt.Errorf("merge resource: %w", rerr) } provOption := make([]metric.Option, 0, 2) if option.reader != nil { provOption = append(provOption, metric.WithReader(option.reader)) } meterProvider := metric.NewMeterProvider(append(provOption, metric.WithResource(res))...) otel.SetMeterProvider(meterProvider) return meterProvider, nil }