pkg/inst-api/instrumenter/instrumenter_builder.go (160 lines of code) (raw):

// Copyright (c) 2024 Alibaba Group Holding Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package instrumenter import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/trace" ) // TODO: add route updater here, now we do not support such controller layer to update route. type InstrumentEnabler interface { Enable() bool } type defaultInstrumentEnabler struct { } func NewDefaultInstrumentEnabler() InstrumentEnabler { return &defaultInstrumentEnabler{} } func (a *defaultInstrumentEnabler) Enable() bool { return true } type Builder[REQUEST any, RESPONSE any] struct { Enabler InstrumentEnabler SpanNameExtractor SpanNameExtractor[REQUEST] SpanKindExtractor SpanKindExtractor[REQUEST] SpanStatusExtractor SpanStatusExtractor[REQUEST, RESPONSE] AttributesExtractors []AttributesExtractor[REQUEST, RESPONSE] OperationListeners []OperationListener ContextCustomizers []ContextCustomizer[REQUEST] SpanSuppressor SpanSuppressor InstVersion string Scope instrumentation.Scope } func (b *Builder[REQUEST, RESPONSE]) Init() *Builder[REQUEST, RESPONSE] { b.Enabler = &defaultInstrumentEnabler{} b.AttributesExtractors = make([]AttributesExtractor[REQUEST, RESPONSE], 0) b.ContextCustomizers = make([]ContextCustomizer[REQUEST], 0) b.SpanStatusExtractor = &defaultSpanStatusExtractor[REQUEST, RESPONSE]{} return b } func (b *Builder[REQUEST, RESPONSE]) SetInstrumentationScope(scope instrumentation.Scope) *Builder[REQUEST, RESPONSE] { b.Scope = scope return b } func (b *Builder[REQUEST, RESPONSE]) SetInstrumentEnabler(enabler InstrumentEnabler) *Builder[REQUEST, RESPONSE] { b.Enabler = enabler return b } func (b *Builder[REQUEST, RESPONSE]) SetSpanNameExtractor(spanNameExtractor SpanNameExtractor[REQUEST]) *Builder[REQUEST, RESPONSE] { b.SpanNameExtractor = spanNameExtractor return b } func (b *Builder[REQUEST, RESPONSE]) SetSpanStatusExtractor(spanStatusExtractor SpanStatusExtractor[REQUEST, RESPONSE]) *Builder[REQUEST, RESPONSE] { b.SpanStatusExtractor = spanStatusExtractor return b } func (b *Builder[REQUEST, RESPONSE]) SetSpanKindExtractor(spanKindExtractor SpanKindExtractor[REQUEST]) *Builder[REQUEST, RESPONSE] { b.SpanKindExtractor = spanKindExtractor return b } func (b *Builder[REQUEST, RESPONSE]) AddAttributesExtractor(attributesExtractor ...AttributesExtractor[REQUEST, RESPONSE]) *Builder[REQUEST, RESPONSE] { b.AttributesExtractors = append(b.AttributesExtractors, attributesExtractor...) return b } func (b *Builder[REQUEST, RESPONSE]) AddOperationListeners(operationListener ...OperationListener) *Builder[REQUEST, RESPONSE] { b.OperationListeners = append(b.OperationListeners, operationListener...) return b } func (b *Builder[REQUEST, RESPONSE]) AddContextCustomizers(contextCustomizers ...ContextCustomizer[REQUEST]) *Builder[REQUEST, RESPONSE] { b.ContextCustomizers = append(b.ContextCustomizers, contextCustomizers...) return b } func (b *Builder[REQUEST, RESPONSE]) BuildInstrumenter() *InternalInstrumenter[REQUEST, RESPONSE] { tracer := otel.GetTracerProvider(). Tracer(b.Scope.Name, trace.WithInstrumentationVersion(b.Scope.Version), trace.WithSchemaURL(b.Scope.SchemaURL)) return &InternalInstrumenter[REQUEST, RESPONSE]{ enabler: b.Enabler, spanNameExtractor: b.SpanNameExtractor, spanKindExtractor: b.SpanKindExtractor, spanStatusExtractor: b.SpanStatusExtractor, attributesExtractors: b.AttributesExtractors, operationListeners: b.OperationListeners, contextCustomizers: b.ContextCustomizers, spanSuppressor: b.buildSpanSuppressor(), tracer: tracer, instVersion: b.InstVersion, } } func (b *Builder[REQUEST, RESPONSE]) BuildInstrumenterWithTracer(tracer trace.Tracer) *InternalInstrumenter[REQUEST, RESPONSE] { return &InternalInstrumenter[REQUEST, RESPONSE]{ enabler: b.Enabler, spanNameExtractor: b.SpanNameExtractor, spanKindExtractor: b.SpanKindExtractor, spanStatusExtractor: b.SpanStatusExtractor, attributesExtractors: b.AttributesExtractors, operationListeners: b.OperationListeners, contextCustomizers: b.ContextCustomizers, spanSuppressor: b.buildSpanSuppressor(), tracer: tracer, instVersion: b.InstVersion, } } func (b *Builder[REQUEST, RESPONSE]) BuildPropagatingToDownstreamInstrumenter(carrierGetter func(REQUEST) propagation.TextMapCarrier, prop propagation.TextMapPropagator) *PropagatingToDownstreamInstrumenter[REQUEST, RESPONSE] { tracer := otel.GetTracerProvider(). Tracer(b.Scope.Name, trace.WithInstrumentationVersion(b.Scope.Version), trace.WithSchemaURL(b.Scope.SchemaURL)) return &PropagatingToDownstreamInstrumenter[REQUEST, RESPONSE]{ base: InternalInstrumenter[REQUEST, RESPONSE]{ enabler: b.Enabler, spanNameExtractor: b.SpanNameExtractor, spanKindExtractor: b.SpanKindExtractor, spanStatusExtractor: b.SpanStatusExtractor, attributesExtractors: b.AttributesExtractors, operationListeners: b.OperationListeners, contextCustomizers: b.ContextCustomizers, spanSuppressor: b.buildSpanSuppressor(), tracer: tracer, instVersion: b.InstVersion, }, carrierGetter: carrierGetter, prop: prop, } } func (b *Builder[REQUEST, RESPONSE]) BuildPropagatingFromUpstreamInstrumenter(carrierGetter func(REQUEST) propagation.TextMapCarrier, prop propagation.TextMapPropagator) *PropagatingFromUpstreamInstrumenter[REQUEST, RESPONSE] { tracer := otel.GetTracerProvider(). Tracer(b.Scope.Name, trace.WithInstrumentationVersion(b.Scope.Version), trace.WithSchemaURL(b.Scope.SchemaURL)) return &PropagatingFromUpstreamInstrumenter[REQUEST, RESPONSE]{ base: InternalInstrumenter[REQUEST, RESPONSE]{ enabler: b.Enabler, spanNameExtractor: b.SpanNameExtractor, spanKindExtractor: b.SpanKindExtractor, spanStatusExtractor: b.SpanStatusExtractor, attributesExtractors: b.AttributesExtractors, operationListeners: b.OperationListeners, spanSuppressor: b.buildSpanSuppressor(), tracer: tracer, instVersion: b.InstVersion, }, carrierGetter: carrierGetter, prop: prop, } } func (b *Builder[REQUEST, RESPONSE]) buildSpanSuppressor() SpanSuppressor { spanSuppressorStrategy := getSpanSuppressionStrategyFromEnv() kvs := make(map[attribute.Key]bool) for _, extractor := range b.AttributesExtractors { provider, ok := extractor.(SpanKeyProvider) if ok { kvs[provider.GetSpanKey()] = true } } kSlice := make([]attribute.Key, 0, len(kvs)) for k := range kvs { kSlice = append(kSlice, k) } return spanSuppressorStrategy.create(kSlice) }