Skip to content

Repository files navigation

spectra

OpenTelemetry instrumentation for Go tests. Make your tests observable and traceable by streaming spans, metrics, and log events to any OTLP collector.

Features

  • Automatic span creation for tests and subtests
  • Log interception (t.Log → OTEL span events)
  • Metrics recording (duration histogram, test counters)
  • Setup/teardown tracing
  • Manual span creation for operations under test
  • OTLP export to any compatible collector

Installation

go get github.com/monkescience/spectra

Quick start

Initialize once in TestMain, then wrap each test with sp.New(t). The examples below assume a package-level sp *spectra.Spectra so every test in the package can use it.

package mypkg_test
import (
"log""os""testing""github.com/monkescience/spectra"
)
varsp*spectra.SpectrafuncTestMain(m*testing.M) {
varerrerrorsp, err=spectra.Init(
spectra.WithServiceName("my-service-tests"),
spectra.WithEndpoint("grpc://localhost:4317"),
spectra.WithInsecure(), // skip TLS verification for local collectors
)
iferr!=nil {
log.Fatalf("spectra init: %v", err)
}
defersp.Shutdown()
os.Exit(m.Run())
}

Usage

Wrap a test

funcTestFeature(t*testing.T) {
st, err:=sp.New(t)
iferr!=nil {
t.Fatalf("spectra: %v", err)
}
// Logs become span eventsst.Log("starting test")
// Add custom attributes to the test spanst.SetAttributes(attribute.String("feature", "login"))
// Subtests become child spansst.Run("validates_input", func(st*spectra.T) {
// test code...
})
}

Trace operations under test

funcTestDatabaseQuery(t*testing.T) {
st, err:=sp.New(t)
iferr!=nil {
t.Fatalf("spectra: %v", err)
}
// Create a child span for the operation you're testingctx, span:=st.StartSpan("db-query")
deferspan.End()
_, err=db.Query(ctx, "SELECT ...")
iferr!=nil {
t.Fatalf("query: %v", err)
}
}

Setup and teardown

funcTestWithFixtures(t*testing.T) {
st, err:=sp.New(t)
iferr!=nil {
t.Fatalf("spectra: %v", err)
}
// Setup gets its own spanst.Setup(func(ctx context.Context) {
seedDatabase(ctx)
})
// Teardown runs on cleanup with its own spanst.Teardown(func(ctx context.Context) {
cleanupDatabase(ctx)
})
st.Run("query", func(st*spectra.T) {
// test with seeded data...
})
}

Install as OTEL globals (opt-in)

By default, spectra keeps its providers local so it does not interfere with code under test that reads otel.GetTracerProvider(). If your code relies on the global providers being spectra's, opt in:

sp, err:=spectra.Init(
spectra.WithServiceName("my-service-tests"),
spectra.WithEndpoint("grpc://localhost:4317"),
spectra.WithSetGlobalProviders(), // previous globals are restored on Shutdown
)

Configuration

OptionDescription
WithServiceName(name)Service name for telemetry (required)
WithEndpoint(endpoint)OTLP collector endpoint with scheme (required)
WithInsecure()gRPC: disable TLS. HTTPS: skip cert verification
WithShutdownTimeout(d)Graceful shutdown timeout (default: 5s)
WithLogger(logger)*slog.Logger for spectra's own operational messages (default: slog.Default())
WithTracerProvider(tp)Use an existing trace.TracerProvider instead of creating one
WithSetGlobalProviders()Install spectra's providers as OTEL globals (off by default)
WithoutTraces()Disable trace collection
WithoutMetrics()Disable metrics collection
WithoutLogs()Disable log capture as span events

Endpoint format

The endpoint must include a scheme:

SchemeProtocolTLS
grpc://host:portgRPCYes, use WithInsecure() to disable
http://host:portHTTPNo
https://host:portHTTPSYes, use WithInsecure() to skip cert verification

Error handling

Spectra surfaces a small set of sentinel errors you can branch on with errors.Is:

ErrorWhenResolution
ErrMissingServiceNamespectra.Init called without WithServiceNamePass WithServiceName("…")
ErrMissingEndpointspectra.Init called without WithEndpointPass WithEndpoint("grpc://…")
ErrInvalidEndpointEndpoint missing a schemeUse grpc://, http://, or https://
ErrNotInitializedsp.New(t) called before spectra.Init() or on a nil *SpectraCall spectra.Init() in TestMain first
ErrAlreadyShutdownOperations attempted after sp.Shutdown()Ensure tests run before shutdown

Telemetry

Traces

  • Test span per sp.New() call
  • Child spans for subtests via st.Run()
  • Setup/teardown spans
  • Custom spans via st.StartSpan()
  • Span status reflects test pass/fail/skip

Metrics

MetricTypeDescription
test.durationHistogramTest execution time in seconds
test.countCounterNumber of tests by status (pass/fail/skip)

Logs

All t.Log(), t.Error(), t.Fatal(), and t.Skip() calls are captured as span events with appropriate severity levels.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages