Bluemage/go/server/interceptor.go

75 lines
2 KiB
Go

package server
import (
"context"
"errors"
"fmt"
"log/slog"
"time"
"connectrpc.com/connect"
"github.com/tigorlazuardi/bluemage/go/pkg/errs"
"github.com/tigorlazuardi/bluemage/go/pkg/telemetry"
"go.opentelemetry.io/otel/trace"
)
func LogInterceptor() connect.UnaryInterceptorFunc {
interceptor := func(next connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, ar connect.AnyRequest) (resp connect.AnyResponse, err error) {
span := trace.SpanFromContext(ctx)
defer func() { telemetry.EndWithStatus(span, err) }()
start := time.Now()
resp, err = next(ctx, ar)
dur := time.Since(start)
if err != nil {
slog.ErrorContext(ctx, "RPC Error",
"procedure", ar.Spec().Procedure,
"method", ar.HTTPMethod(),
"duration", fmt.Sprintf("%.3fs", dur.Seconds()),
"error", errs.DrillToError(err),
"span.id", span.SpanContext().SpanID().String(),
"trace.id", span.SpanContext().TraceID().String(),
)
} else {
slog.InfoContext(ctx, "RPC Call",
"procedure", ar.Spec().Procedure,
"method", ar.HTTPMethod(),
"duration", fmt.Sprintf("%.3fs", dur.Seconds()),
"span.id", span.SpanContext().SpanID().String(),
"trace.id", span.SpanContext().TraceID().String(),
)
}
return resp, err
}
}
return connect.UnaryInterceptorFunc(interceptor)
}
func ErrorMessageInterceptor() connect.UnaryInterceptorFunc {
return func(uf connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, ar connect.AnyRequest) (connect.AnyResponse, error) {
resp, err := uf(ctx, ar)
if err == nil {
return resp, err
}
span := trace.SpanFromContext(ctx)
if !span.SpanContext().IsValid() {
return resp, err
}
if cerr := new(connect.Error); errors.As(err, &cerr) {
if e := errs.FindError(cerr); e != nil {
msg := e.GetMessage()
spanContext := span.SpanContext()
traceId := spanContext.TraceID().String()
e.Message("%s|%s", traceId, msg)
}
}
return resp, err
}
}
}