mirror of
https://github.com/hanzoai/telemetry.git
synced 2026-10-30 20:01:49 +00:00
#### Description This PR splits the code handling component attribute injection, currently in `internal/telemetry` and `internal/telemetry/componentattribute`, into three parts: - the part meant to be called by components to drop unwanted injected attributes, which remains in `internal/telemetry`; - the part which handles copying Zap logs to an OTel LoggerProvider (where injected attributes are surfaced as instrumentation scope attributes), which is moved into `service/telemetry/otelconftelemetry`, since this "copying" behavior is specific to the otelconf-based telemetry provider; - the rest is moved into `service/internal/componentattribute`. The main goals of this split are: - to address #13842, by moving most dependencies of `componentattribute` into the service - to prepare for the availability of alternate telemetry providers. I also rewrote a lot of the attribute injection code along the way: - Instead of adding an unexported field in `TelemetrySettings` to store the current set of injected attributes, this set is now stored inside the provider wrappers (which was already partly the case). This allowed me to move the `TelemetrySettings` definition back into `component`, removing the dependency it had on `componentattribute`. - I completely changed the approach for injection in logs. Instead of a chain of custom core wrappers with a `withAttributeSet` method, injected attributes are now set through the standard `zapcore.Core.With` method. By introducing a custom `ObjectMarshaler`, we can make injected attributes act like regular Zap fields, while also allowing special handling in the otelzap wrapper core, which will set them as instrumentation scope attributes instead of log record attributes. If I'm not mistaken, this PR should have no externally-visible changes, so no changelog should be necessary. (Except maybe the `_ struct{}` in `TelemetrySettings`, but there was no changelog when we added those elsewhere) #### Link to tracking issue Updates #13842 #### Testing The large amounts of splitting and refactoring led me to abandon the existing tests, as they would be too hard to adapt. I wrote new tests for the code in `service/telemetry/otelconftelemetry` and `service/internal/componentattribute`, which hopefully should fill that gap appropriately.
82 lines
2.2 KiB
Go
82 lines
2.2 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package componentattribute // import "go.opentelemetry.io/collector/service/internal/componentattribute"
|
|
|
|
import (
|
|
"slices"
|
|
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
|
|
"go.opentelemetry.io/collector/internal/telemetry"
|
|
)
|
|
|
|
// This wrapper around zapcore.Field tells the Zap -> OTel bridge that the field
|
|
// should be turned into an instrumentation scope instead of a set of log record attributes.
|
|
type scopeAttributesField struct {
|
|
fields []zapcore.Field
|
|
attrs []attribute.KeyValue
|
|
}
|
|
|
|
var _ zapcore.ObjectMarshaler = scopeAttributesField{}
|
|
|
|
func (saf scopeAttributesField) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
|
for _, field := range saf.fields {
|
|
field.AddTo(enc)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func makeScopeField(attrs []attribute.KeyValue) zap.Field {
|
|
return zap.Inline(scopeAttributesField{
|
|
fields: telemetry.ToZapFields(attrs),
|
|
attrs: attrs,
|
|
})
|
|
}
|
|
|
|
func ExtractLogScopeAttributes(field zap.Field) ([]attribute.KeyValue, bool) {
|
|
if field.Type != zapcore.InlineMarshalerType {
|
|
return nil, false
|
|
}
|
|
saf, ok := field.Interface.(scopeAttributesField)
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
return saf.attrs, true
|
|
}
|
|
|
|
type coreWithAttributes struct {
|
|
zapcore.Core
|
|
sourceCore zapcore.Core
|
|
attrs []attribute.KeyValue
|
|
withFields []zap.Field
|
|
}
|
|
|
|
var _ zapcore.Core = coreWithAttributes{}
|
|
|
|
func (cwa coreWithAttributes) With(fields []zapcore.Field) zapcore.Core {
|
|
cwa.withFields = append(cwa.withFields, fields...)
|
|
cwa.Core = cwa.Core.With(fields)
|
|
return cwa
|
|
}
|
|
|
|
func LoggerWithAttributes(logger *zap.Logger, attrs []attribute.KeyValue) *zap.Logger {
|
|
return logger.WithOptions(zap.WrapCore(func(c zapcore.Core) zapcore.Core {
|
|
return coreWithAttributes{
|
|
Core: c.With([]zap.Field{makeScopeField(attrs)}),
|
|
sourceCore: c,
|
|
attrs: attrs,
|
|
}
|
|
}))
|
|
}
|
|
|
|
func (cwa coreWithAttributes) DropInjectedAttributes(droppedAttrs ...string) zapcore.Core {
|
|
cwa.attrs = slices.DeleteFunc(slices.Clone(cwa.attrs), func(kv attribute.KeyValue) bool {
|
|
return slices.Contains(droppedAttrs, string(kv.Key))
|
|
})
|
|
cwa.Core = cwa.sourceCore.With(append([]zap.Field{makeScopeField(cwa.attrs)}, cwa.withFields...))
|
|
return cwa
|
|
}
|