mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
feat: create tracing.SlogSink for storing logs as span events (#4962)
This commit is contained in:
116
coderd/tracing/slog.go
Normal file
116
coderd/tracing/slog.go
Normal file
@ -0,0 +1,116 @@
|
||||
package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"cdr.dev/slog"
|
||||
)
|
||||
|
||||
type SlogSink struct{}
|
||||
|
||||
var _ slog.Sink = SlogSink{}
|
||||
|
||||
// LogEntry implements slog.Sink. All entries are added as events to the span
|
||||
// in the context. If no span is present, the entry is dropped.
|
||||
func (SlogSink) LogEntry(ctx context.Context, e slog.SinkEntry) {
|
||||
span := trace.SpanFromContext(ctx)
|
||||
if !span.IsRecording() {
|
||||
// If the span is a noopSpan or isn't recording, we don't want to
|
||||
// compute the attributes (which is expensive) below.
|
||||
return
|
||||
}
|
||||
|
||||
attributes := []attribute.KeyValue{
|
||||
attribute.String("slog.time", e.Time.Format(time.RFC3339Nano)),
|
||||
attribute.String("slog.logger", strings.Join(e.LoggerNames, ".")),
|
||||
attribute.String("slog.level", e.Level.String()),
|
||||
attribute.String("slog.message", e.Message),
|
||||
attribute.String("slog.func", e.Func),
|
||||
attribute.String("slog.file", e.File),
|
||||
attribute.Int64("slog.line", int64(e.Line)),
|
||||
}
|
||||
attributes = append(attributes, slogFieldsToAttributes(e.Fields)...)
|
||||
|
||||
name := fmt.Sprintf("log: %s: %s", e.Level, e.Message)
|
||||
span.AddEvent(name, trace.WithAttributes(attributes...))
|
||||
}
|
||||
|
||||
// Sync implements slog.Sink. No-op as syncing is handled externally by otel.
|
||||
func (SlogSink) Sync() {}
|
||||
|
||||
func slogFieldsToAttributes(m slog.Map) []attribute.KeyValue {
|
||||
attrs := make([]attribute.KeyValue, 0, len(m))
|
||||
for _, f := range m {
|
||||
var value attribute.Value
|
||||
switch v := f.Value.(type) {
|
||||
case bool:
|
||||
value = attribute.BoolValue(v)
|
||||
case []bool:
|
||||
value = attribute.BoolSliceValue(v)
|
||||
case float32:
|
||||
value = attribute.Float64Value(float64(v))
|
||||
// no float32 slice method
|
||||
case float64:
|
||||
value = attribute.Float64Value(v)
|
||||
case []float64:
|
||||
value = attribute.Float64SliceValue(v)
|
||||
case int:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
case []int:
|
||||
value = attribute.IntSliceValue(v)
|
||||
case int8:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
// no int8 slice method
|
||||
case int16:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
// no int16 slice method
|
||||
case int32:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
// no int32 slice method
|
||||
case int64:
|
||||
value = attribute.Int64Value(v)
|
||||
case []int64:
|
||||
value = attribute.Int64SliceValue(v)
|
||||
case uint:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
// no uint slice method
|
||||
case uint8:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
// no uint8 slice method
|
||||
case uint16:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
// no uint16 slice method
|
||||
case uint32:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
// no uint32 slice method
|
||||
case uint64:
|
||||
value = attribute.Int64Value(int64(v))
|
||||
// no uint64 slice method
|
||||
case string:
|
||||
value = attribute.StringValue(v)
|
||||
case []string:
|
||||
value = attribute.StringSliceValue(v)
|
||||
case time.Duration:
|
||||
value = attribute.StringValue(v.String())
|
||||
case time.Time:
|
||||
value = attribute.StringValue(v.Format(time.RFC3339Nano))
|
||||
case fmt.Stringer:
|
||||
value = attribute.StringValue(v.String())
|
||||
}
|
||||
|
||||
if value.Type() != attribute.INVALID {
|
||||
attrs = append(attrs, attribute.KeyValue{
|
||||
Key: attribute.Key(f.Name),
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return attrs
|
||||
}
|
Reference in New Issue
Block a user