[chore] Simplify the OTEL setup (#4110)

# Description

This simplifies our OTEL setup by:

* Getting rid of some deprecated things.
* Using `autoexport` and letting things get configured by the `OTEL_` environment variables.
* Removing all the unnecessary config options.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4110
Reviewed-by: tobi <kipvandenbos@noreply.codeberg.org>
Co-authored-by: Daenney <daenney@noreply.codeberg.org>
Co-committed-by: Daenney <daenney@noreply.codeberg.org>
This commit is contained in:
Daenney 2025-05-05 16:22:45 +00:00 committed by tobi
commit ecbdc4227b
145 changed files with 21740 additions and 1319 deletions

View file

@ -0,0 +1,3 @@
# SDK Trace test
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/sdk/trace/tracetest)](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace/tracetest)

View file

@ -0,0 +1,74 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package tracetest is a testing helper package for the SDK. User can
// configure no-op or in-memory exporters to verify different SDK behaviors or
// custom instrumentation.
package tracetest // import "go.opentelemetry.io/otel/sdk/trace/tracetest"
import (
"context"
"sync"
"go.opentelemetry.io/otel/sdk/trace"
)
var _ trace.SpanExporter = (*NoopExporter)(nil)
// NewNoopExporter returns a new no-op exporter.
func NewNoopExporter() *NoopExporter {
return new(NoopExporter)
}
// NoopExporter is an exporter that drops all received spans and performs no
// action.
type NoopExporter struct{}
// ExportSpans handles export of spans by dropping them.
func (nsb *NoopExporter) ExportSpans(context.Context, []trace.ReadOnlySpan) error { return nil }
// Shutdown stops the exporter by doing nothing.
func (nsb *NoopExporter) Shutdown(context.Context) error { return nil }
var _ trace.SpanExporter = (*InMemoryExporter)(nil)
// NewInMemoryExporter returns a new InMemoryExporter.
func NewInMemoryExporter() *InMemoryExporter {
return new(InMemoryExporter)
}
// InMemoryExporter is an exporter that stores all received spans in-memory.
type InMemoryExporter struct {
mu sync.Mutex
ss SpanStubs
}
// ExportSpans handles export of spans by storing them in memory.
func (imsb *InMemoryExporter) ExportSpans(_ context.Context, spans []trace.ReadOnlySpan) error {
imsb.mu.Lock()
defer imsb.mu.Unlock()
imsb.ss = append(imsb.ss, SpanStubsFromReadOnlySpans(spans)...)
return nil
}
// Shutdown stops the exporter by clearing spans held in memory.
func (imsb *InMemoryExporter) Shutdown(context.Context) error {
imsb.Reset()
return nil
}
// Reset the current in-memory storage.
func (imsb *InMemoryExporter) Reset() {
imsb.mu.Lock()
defer imsb.mu.Unlock()
imsb.ss = nil
}
// GetSpans returns the current in-memory stored spans.
func (imsb *InMemoryExporter) GetSpans() SpanStubs {
imsb.mu.Lock()
defer imsb.mu.Unlock()
ret := make(SpanStubs, len(imsb.ss))
copy(ret, imsb.ss)
return ret
}

View file

@ -0,0 +1,94 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package tracetest // import "go.opentelemetry.io/otel/sdk/trace/tracetest"
import (
"context"
"sync"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
// SpanRecorder records started and ended spans.
type SpanRecorder struct {
startedMu sync.RWMutex
started []sdktrace.ReadWriteSpan
endedMu sync.RWMutex
ended []sdktrace.ReadOnlySpan
}
var _ sdktrace.SpanProcessor = (*SpanRecorder)(nil)
// NewSpanRecorder returns a new initialized SpanRecorder.
func NewSpanRecorder() *SpanRecorder {
return new(SpanRecorder)
}
// OnStart records started spans.
//
// This method is safe to be called concurrently.
func (sr *SpanRecorder) OnStart(_ context.Context, s sdktrace.ReadWriteSpan) {
sr.startedMu.Lock()
defer sr.startedMu.Unlock()
sr.started = append(sr.started, s)
}
// OnEnd records completed spans.
//
// This method is safe to be called concurrently.
func (sr *SpanRecorder) OnEnd(s sdktrace.ReadOnlySpan) {
sr.endedMu.Lock()
defer sr.endedMu.Unlock()
sr.ended = append(sr.ended, s)
}
// Shutdown does nothing.
//
// This method is safe to be called concurrently.
func (sr *SpanRecorder) Shutdown(context.Context) error {
return nil
}
// ForceFlush does nothing.
//
// This method is safe to be called concurrently.
func (sr *SpanRecorder) ForceFlush(context.Context) error {
return nil
}
// Started returns a copy of all started spans that have been recorded.
//
// This method is safe to be called concurrently.
func (sr *SpanRecorder) Started() []sdktrace.ReadWriteSpan {
sr.startedMu.RLock()
defer sr.startedMu.RUnlock()
dst := make([]sdktrace.ReadWriteSpan, len(sr.started))
copy(dst, sr.started)
return dst
}
// Reset clears the recorded spans.
//
// This method is safe to be called concurrently.
func (sr *SpanRecorder) Reset() {
sr.startedMu.Lock()
sr.endedMu.Lock()
defer sr.startedMu.Unlock()
defer sr.endedMu.Unlock()
sr.started = nil
sr.ended = nil
}
// Ended returns a copy of all ended spans that have been recorded.
//
// This method is safe to be called concurrently.
func (sr *SpanRecorder) Ended() []sdktrace.ReadOnlySpan {
sr.endedMu.RLock()
defer sr.endedMu.RUnlock()
dst := make([]sdktrace.ReadOnlySpan, len(sr.ended))
copy(dst, sr.ended)
return dst
}

View file

@ -0,0 +1,166 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package tracetest // import "go.opentelemetry.io/otel/sdk/trace/tracetest"
import (
"time"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/resource"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)
// SpanStubs is a slice of SpanStub use for testing an SDK.
type SpanStubs []SpanStub
// SpanStubsFromReadOnlySpans returns SpanStubs populated from ro.
func SpanStubsFromReadOnlySpans(ro []tracesdk.ReadOnlySpan) SpanStubs {
if len(ro) == 0 {
return nil
}
s := make(SpanStubs, 0, len(ro))
for _, r := range ro {
s = append(s, SpanStubFromReadOnlySpan(r))
}
return s
}
// Snapshots returns s as a slice of ReadOnlySpans.
func (s SpanStubs) Snapshots() []tracesdk.ReadOnlySpan {
if len(s) == 0 {
return nil
}
ro := make([]tracesdk.ReadOnlySpan, len(s))
for i := 0; i < len(s); i++ {
ro[i] = s[i].Snapshot()
}
return ro
}
// SpanStub is a stand-in for a Span.
type SpanStub struct {
Name string
SpanContext trace.SpanContext
Parent trace.SpanContext
SpanKind trace.SpanKind
StartTime time.Time
EndTime time.Time
Attributes []attribute.KeyValue
Events []tracesdk.Event
Links []tracesdk.Link
Status tracesdk.Status
DroppedAttributes int
DroppedEvents int
DroppedLinks int
ChildSpanCount int
Resource *resource.Resource
InstrumentationScope instrumentation.Scope
// Deprecated: use InstrumentationScope instead.
InstrumentationLibrary instrumentation.Library //nolint:staticcheck // This method needs to be define for backwards compatibility
}
// SpanStubFromReadOnlySpan returns a SpanStub populated from ro.
func SpanStubFromReadOnlySpan(ro tracesdk.ReadOnlySpan) SpanStub {
if ro == nil {
return SpanStub{}
}
return SpanStub{
Name: ro.Name(),
SpanContext: ro.SpanContext(),
Parent: ro.Parent(),
SpanKind: ro.SpanKind(),
StartTime: ro.StartTime(),
EndTime: ro.EndTime(),
Attributes: ro.Attributes(),
Events: ro.Events(),
Links: ro.Links(),
Status: ro.Status(),
DroppedAttributes: ro.DroppedAttributes(),
DroppedEvents: ro.DroppedEvents(),
DroppedLinks: ro.DroppedLinks(),
ChildSpanCount: ro.ChildSpanCount(),
Resource: ro.Resource(),
InstrumentationScope: ro.InstrumentationScope(),
InstrumentationLibrary: ro.InstrumentationScope(),
}
}
// Snapshot returns a read-only copy of the SpanStub.
func (s SpanStub) Snapshot() tracesdk.ReadOnlySpan {
scopeOrLibrary := s.InstrumentationScope
if scopeOrLibrary.Name == "" && scopeOrLibrary.Version == "" && scopeOrLibrary.SchemaURL == "" {
scopeOrLibrary = s.InstrumentationLibrary
}
return spanSnapshot{
name: s.Name,
spanContext: s.SpanContext,
parent: s.Parent,
spanKind: s.SpanKind,
startTime: s.StartTime,
endTime: s.EndTime,
attributes: s.Attributes,
events: s.Events,
links: s.Links,
status: s.Status,
droppedAttributes: s.DroppedAttributes,
droppedEvents: s.DroppedEvents,
droppedLinks: s.DroppedLinks,
childSpanCount: s.ChildSpanCount,
resource: s.Resource,
instrumentationScope: scopeOrLibrary,
}
}
type spanSnapshot struct {
// Embed the interface to implement the private method.
tracesdk.ReadOnlySpan
name string
spanContext trace.SpanContext
parent trace.SpanContext
spanKind trace.SpanKind
startTime time.Time
endTime time.Time
attributes []attribute.KeyValue
events []tracesdk.Event
links []tracesdk.Link
status tracesdk.Status
droppedAttributes int
droppedEvents int
droppedLinks int
childSpanCount int
resource *resource.Resource
instrumentationScope instrumentation.Scope
}
func (s spanSnapshot) Name() string { return s.name }
func (s spanSnapshot) SpanContext() trace.SpanContext { return s.spanContext }
func (s spanSnapshot) Parent() trace.SpanContext { return s.parent }
func (s spanSnapshot) SpanKind() trace.SpanKind { return s.spanKind }
func (s spanSnapshot) StartTime() time.Time { return s.startTime }
func (s spanSnapshot) EndTime() time.Time { return s.endTime }
func (s spanSnapshot) Attributes() []attribute.KeyValue { return s.attributes }
func (s spanSnapshot) Links() []tracesdk.Link { return s.links }
func (s spanSnapshot) Events() []tracesdk.Event { return s.events }
func (s spanSnapshot) Status() tracesdk.Status { return s.status }
func (s spanSnapshot) DroppedAttributes() int { return s.droppedAttributes }
func (s spanSnapshot) DroppedLinks() int { return s.droppedLinks }
func (s spanSnapshot) DroppedEvents() int { return s.droppedEvents }
func (s spanSnapshot) ChildSpanCount() int { return s.childSpanCount }
func (s spanSnapshot) Resource() *resource.Resource { return s.resource }
func (s spanSnapshot) InstrumentationScope() instrumentation.Scope {
return s.instrumentationScope
}
func (s spanSnapshot) InstrumentationLibrary() instrumentation.Library { //nolint:staticcheck // This method needs to be define for backwards compatibility
return s.instrumentationScope
}