refactor: remove Sentry integration and replace with OpenTelemetry
Remove Sentry dependencies and configuration. Introduce monitoring setup for OpenTelemetry. Update logging to include log format options, and replace Sentry error handling middleware with monitoring handlers for GraphQL playground. Adjust environment variable handling to enhance configuration clarity and flexibility.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
func AroundOperations(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||
op := graphql.GetOperationContext(ctx)
|
||||
spanName := fmt.Sprintf("graphql:operation:%s", op.OperationName)
|
||||
// Span always injected in the http handler above
|
||||
sp := trace.SpanFromContext(ctx)
|
||||
if sp != nil {
|
||||
sp.SetName(spanName)
|
||||
}
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
func AroundRootFields(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
|
||||
oc := graphql.GetRootFieldContext(ctx)
|
||||
spanCtx, span := StartSpan(ctx, fmt.Sprintf("graphql:rootfield:%s", oc.Field.Name))
|
||||
defer span.Finish()
|
||||
return next(spanCtx)
|
||||
}
|
||||
|
||||
func AroundFields(ctx context.Context, next graphql.Resolver) (res any, err error) {
|
||||
oc := graphql.GetFieldContext(ctx)
|
||||
var span Span
|
||||
if oc.IsResolver {
|
||||
ctx, span = StartSpan(ctx, fmt.Sprintf("graphql:field:%s", oc.Field.Name))
|
||||
}
|
||||
defer func() {
|
||||
if span != nil {
|
||||
span.Finish()
|
||||
}
|
||||
}()
|
||||
return next(ctx)
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
||||
"go.opentelemetry.io/otel/exporters/stdout/stdoutlog"
|
||||
"go.opentelemetry.io/otel/log/global"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/sdk/log"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/trace"
|
||||
)
|
||||
|
||||
// SetupOTelSDK bootstraps the OpenTelemetry pipeline.
|
||||
func SetupOTelSDK(ctx context.Context, enabled bool, serviceName, buildVersion, environment string) (func(context.Context) error, error) {
|
||||
if os.Getenv("OTEL_RESOURCE_ATTRIBUTES") == "" {
|
||||
if err := os.Setenv("OTEL_RESOURCE_ATTRIBUTES", fmt.Sprintf("service.name=%s,service.version=%s,service.environment=%s", serviceName, buildVersion, environment)); err != nil {
|
||||
return func(context.Context) error {
|
||||
return nil
|
||||
}, err
|
||||
}
|
||||
}
|
||||
var shutdownFuncs []func(context.Context) error
|
||||
if !enabled {
|
||||
return func(context.Context) error {
|
||||
return nil
|
||||
}, nil
|
||||
}
|
||||
shutdown := func(ctx context.Context) error {
|
||||
var err error
|
||||
for _, fn := range shutdownFuncs {
|
||||
err = errors.Join(err, fn(ctx))
|
||||
}
|
||||
shutdownFuncs = nil
|
||||
return err
|
||||
}
|
||||
|
||||
// handleErr calls shutdown for cleanup and makes sure that all errors are returned.
|
||||
handleErr := func(inErr error) (func(context.Context) error, error) {
|
||||
return nil, errors.Join(inErr, shutdown(ctx))
|
||||
}
|
||||
|
||||
// Set up the propagator.
|
||||
prop := propagation.NewCompositeTextMapPropagator(
|
||||
propagation.TraceContext{},
|
||||
propagation.Baggage{},
|
||||
)
|
||||
otel.SetTextMapPropagator(prop)
|
||||
|
||||
traceExporter, err := otlptracehttp.New(ctx)
|
||||
if err != nil {
|
||||
return handleErr(err)
|
||||
}
|
||||
shutdownFuncs = append(shutdownFuncs, traceExporter.Shutdown)
|
||||
|
||||
tracerProvider := trace.NewTracerProvider(
|
||||
trace.WithBatcher(traceExporter,
|
||||
trace.WithBatchTimeout(5*time.Second)),
|
||||
)
|
||||
shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown)
|
||||
otel.SetTracerProvider(tracerProvider)
|
||||
|
||||
logExporter, err := stdoutlog.New()
|
||||
if err != nil {
|
||||
return handleErr(err)
|
||||
}
|
||||
processor := log.NewSimpleProcessor(logExporter)
|
||||
logProvider := log.NewLoggerProvider(log.WithProcessor(processor))
|
||||
|
||||
global.SetLoggerProvider(logProvider)
|
||||
shutdownFuncs = append(shutdownFuncs, logProvider.Shutdown)
|
||||
|
||||
exp, err := otlpmetrichttp.New(ctx)
|
||||
if err != nil {
|
||||
return handleErr(err)
|
||||
}
|
||||
meterProvider := metric.NewMeterProvider(metric.WithReader(metric.NewPeriodicReader(exp)))
|
||||
shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown)
|
||||
|
||||
otel.SetMeterProvider(meterProvider)
|
||||
return shutdown, err
|
||||
}
|
||||
|
||||
func Handler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||
spanCtx, s := StartSpan(ctx, "http")
|
||||
defer s.Finish()
|
||||
|
||||
h.ServeHTTP(w, r.WithContext(spanCtx))
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
type Span interface {
|
||||
Context() context.Context
|
||||
Finish()
|
||||
}
|
||||
|
||||
type span struct {
|
||||
otelSpan trace.Span
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (s *span) Finish() {
|
||||
s.otelSpan.End()
|
||||
}
|
||||
|
||||
func (s *span) Context() context.Context {
|
||||
return s.ctx
|
||||
}
|
||||
|
||||
func StartSpan(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, Span) {
|
||||
ctx, otelSpan := otel.Tracer("").Start(ctx, name, opts...)
|
||||
|
||||
return ctx, &span{
|
||||
otelSpan: otelSpan,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
type TraceHandlerFunc func(ctx context.Context, name string) (context.Context, func())
|
||||
|
||||
func (t TraceHandlerFunc) Trace(tx context.Context, name string) (context.Context, func()) {
|
||||
return t(tx, name)
|
||||
}
|
||||
|
||||
func Trace(ctx context.Context, name string) (context.Context, func()) {
|
||||
ctx, s := StartSpan(ctx, name)
|
||||
return ctx, s.Finish
|
||||
}
|
||||
Reference in New Issue
Block a user