203 lines
5.0 KiB
Go
203 lines
5.0 KiB
Go
package tracer
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
gelfexporter "maal/observer/pkg/gelf_exporter"
|
|
"os"
|
|
"runtime"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
fiberOpentelemetry "github.com/psmarcin/fiber-opentelemetry/pkg/fiber-otel"
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/codes"
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
|
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
|
|
"go.opentelemetry.io/otel/sdk/resource"
|
|
trc "go.opentelemetry.io/otel/sdk/trace"
|
|
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
|
trace "go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
var (
|
|
TracingError error = nil
|
|
TP trc.TracerProvider
|
|
)
|
|
|
|
type CustomExporter struct {
|
|
jaeger *otlptrace.Exporter
|
|
stdouttrace *stdouttrace.Exporter
|
|
}
|
|
|
|
type Config struct {
|
|
AppName string
|
|
JaegerUrl string
|
|
GelfUrl string
|
|
Version string
|
|
}
|
|
|
|
func NewCustomExporter(jaegerUrl string) (trc.SpanExporter, error) {
|
|
var jaeg *otlptrace.Exporter
|
|
var outrace *stdouttrace.Exporter
|
|
var err error
|
|
|
|
outrace, err = stdouttrace.New(
|
|
stdouttrace.WithWriter(os.Stdout),
|
|
stdouttrace.WithPrettyPrint(),
|
|
stdouttrace.WithoutTimestamps(),
|
|
)
|
|
if err != nil {
|
|
return &CustomExporter{}, err
|
|
}
|
|
|
|
if len(jaegerUrl) > 0 {
|
|
jaeg = otlptracehttp.NewUnstarted(otlptracehttp.WithEndpointURL(jaegerUrl))
|
|
}
|
|
|
|
return &CustomExporter{
|
|
jaeger: jaeg,
|
|
stdouttrace: outrace,
|
|
}, nil
|
|
|
|
}
|
|
|
|
func (e *CustomExporter) ExportSpans(ctx context.Context, spans []trc.ReadOnlySpan) error {
|
|
if TracingError == nil {
|
|
if e.jaeger != nil {
|
|
err := e.jaeger.ExportSpans(ctx, spans)
|
|
return err
|
|
} else {
|
|
return e.printOnlyOnError(ctx, spans)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *CustomExporter) printOnlyOnError(ctx context.Context, spans []trc.ReadOnlySpan) error {
|
|
var err error
|
|
for _, s := range spans {
|
|
if s.Status().Code == codes.Error {
|
|
err = e.stdouttrace.ExportSpans(ctx, spans)
|
|
break
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (e *CustomExporter) Shutdown(ctx context.Context) error {
|
|
if e.jaeger != nil {
|
|
e.stdouttrace.Shutdown(ctx)
|
|
return e.jaeger.Shutdown(ctx)
|
|
} else {
|
|
return e.stdouttrace.Shutdown(ctx)
|
|
}
|
|
}
|
|
|
|
func newResource(config Config) *resource.Resource {
|
|
r := resource.NewWithAttributes(
|
|
semconv.SchemaURL,
|
|
semconv.ServiceNameKey.String(config.AppName),
|
|
semconv.ServiceVersionKey.String(config.Version),
|
|
attribute.String("service.provider", "maal"),
|
|
)
|
|
return r
|
|
}
|
|
|
|
func NewTracer(config Config) func(*fiber.Ctx) error {
|
|
l := log.New(os.Stdout, "", 0)
|
|
|
|
var tracerProviders []trc.TracerProviderOption
|
|
|
|
otlpExporter := otlptracehttp.NewUnstarted(otlptracehttp.WithEndpointURL(config.JaegerUrl))
|
|
|
|
gelfExporter, err := gelfexporter.New(
|
|
gelfexporter.WithGelfUrl(config.GelfUrl),
|
|
gelfexporter.WithAppName("salego"),
|
|
)
|
|
if err != nil {
|
|
l.Fatal(err)
|
|
}
|
|
tracerProviders = append(tracerProviders, trc.WithBatcher(otlpExporter))
|
|
tracerProviders = append(tracerProviders, trc.WithBatcher(gelfExporter))
|
|
tracerProviders = append(tracerProviders, trc.WithResource(newResource(config)))
|
|
|
|
TP = *trc.NewTracerProvider(tracerProviders...)
|
|
|
|
otel.SetTracerProvider(&TP)
|
|
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {
|
|
if err != TracingError {
|
|
TracingError = err
|
|
log.Println(err)
|
|
}
|
|
}))
|
|
|
|
tracer := TP.Tracer("fiber-otel-router")
|
|
|
|
return fiberOpentelemetry.New(
|
|
fiberOpentelemetry.Config{
|
|
Tracer: tracer,
|
|
SpanName: "{{ .Method }} {{ .Path }}",
|
|
TracerStartAttributes: []trace.SpanStartOption{
|
|
trace.WithSpanKind(trace.SpanKindServer),
|
|
trace.WithNewRoot(),
|
|
},
|
|
},
|
|
)
|
|
}
|
|
|
|
func ShutdownTracer() {
|
|
if err := TP.Shutdown(context.Background()); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func Handler(fc *fiber.Ctx) (context.Context, trace.Span) {
|
|
simpleCtx, span := fiberOpentelemetry.Tracer.Start(fc.UserContext(), fc.OriginalURL())
|
|
fc.SetUserContext(simpleCtx)
|
|
|
|
_, file, line, _ := runtime.Caller(1)
|
|
span.SetAttributes(
|
|
attribute.String("service.layer", "handler"),
|
|
attribute.String("file", file),
|
|
attribute.String("line", fmt.Sprintf("%d", line)),
|
|
)
|
|
|
|
return simpleCtx, span
|
|
}
|
|
|
|
func Service(c context.Context, serviceName string, spanName string) (context.Context, trace.Span) {
|
|
simpleCtx, span := fiberOpentelemetry.Tracer.Start(c, spanName)
|
|
var attribs []attribute.KeyValue
|
|
|
|
_, file, line, _ := runtime.Caller(1)
|
|
attribs = append(
|
|
attribs,
|
|
attribute.String("service.name", serviceName),
|
|
attribute.String("service.layer", "service"),
|
|
attribute.String("file", file),
|
|
attribute.String("line", fmt.Sprintf("%d", line)),
|
|
)
|
|
|
|
span.SetAttributes(attribs...)
|
|
|
|
return simpleCtx, span
|
|
}
|
|
|
|
func Repository(c context.Context, repositoryName string, spanName string) (context.Context, trace.Span) {
|
|
ctx2, span := fiberOpentelemetry.Tracer.Start(c, spanName)
|
|
var attribs []attribute.KeyValue
|
|
|
|
_, file, line, _ := runtime.Caller(1)
|
|
attribs = append(attribs,
|
|
attribute.String("service.repository", repositoryName),
|
|
attribute.String("file", file),
|
|
attribute.String("line", fmt.Sprintf("%d", line)),
|
|
)
|
|
span.SetAttributes(attribs...)
|
|
|
|
return ctx2, span
|
|
}
|