github.com/safedep/dry@v0.0.0-20241016050132-a15651f0548b/obs/tracing.go (about) 1 package obs 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "strconv" 8 9 "github.com/safedep/dry/log" 10 "github.com/safedep/dry/utils" 11 "go.opentelemetry.io/otel" 12 "go.opentelemetry.io/otel/attribute" 13 "go.opentelemetry.io/otel/codes" 14 "go.opentelemetry.io/otel/exporters/otlp/otlptrace" 15 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" 16 "go.opentelemetry.io/otel/propagation" 17 "go.opentelemetry.io/otel/sdk/resource" 18 sdktrace "go.opentelemetry.io/otel/sdk/trace" 19 "go.opentelemetry.io/otel/trace" 20 ) 21 22 const ( 23 tracerControlEnvKey = "APP_SERVICE_OBS_ENABLED" 24 tracerServiceNameEnvKey = "APP_SERVICE_NAME" 25 tracerServiceEnvEnvKey = "APP_SERVICE_ENV" 26 tracerServiceLabelEnvKey = "APP_SERVICE_LABELS" 27 tracerOtelExporterUrlEnvKey = "APP_OTEL_EXPORTER_OTLP_ENDPOINT" 28 ) 29 30 var ( 31 globalTracer = otel.Tracer("NOP") 32 ) 33 34 // InitTracing initializes the global tracer 35 func InitTracing() func(context.Context) error { 36 if !isTracingEnabled() { 37 log.Debugf("Tracing is not enabled") 38 return func(ctx context.Context) error { return nil } 39 } 40 41 serviceName := os.Getenv(tracerServiceNameEnvKey) 42 serviceEnv := os.Getenv(tracerServiceEnvEnvKey) 43 otlpExporterUrl := os.Getenv(tracerOtelExporterUrlEnvKey) 44 45 if utils.IsEmptyString(serviceName) || utils.IsEmptyString(otlpExporterUrl) { 46 panic("tracer is enable but required environment is not defined") 47 } 48 49 // NOTE: We expect the collector to be a sidecar 50 // TODO: Revisit this for using a secure channel 51 exporter, err := otlptrace.New( 52 context.Background(), 53 otlptracegrpc.NewClient( 54 otlptracegrpc.WithInsecure(), 55 otlptracegrpc.WithEndpoint(otlpExporterUrl), 56 ), 57 ) 58 59 if err != nil { 60 panic(fmt.Sprintf("error creating otlp exporter: %v", err)) 61 } 62 63 resources, err := resource.New( 64 context.Background(), 65 resource.WithAttributes( 66 attribute.String("service.name", serviceName), 67 attribute.String("service.environment", serviceEnv), 68 attribute.String("service.language", "go"), 69 ), 70 ) 71 72 if err != nil { 73 panic(fmt.Sprintf("error creating otlp resource: %v", err)) 74 } 75 76 otel.SetTracerProvider( 77 sdktrace.NewTracerProvider( 78 sdktrace.WithSampler(sdktrace.AlwaysSample()), 79 sdktrace.WithBatcher(exporter), 80 sdktrace.WithResource(resources), 81 ), 82 ) 83 84 otel.SetTextMapPropagator(propagation.TraceContext{}) 85 globalTracer = otel.Tracer(serviceName) 86 87 log.Debugf("Tracer initialized for service=%s env=%s", 88 serviceName, serviceEnv) 89 90 return exporter.Shutdown 91 } 92 93 func ShutdownTracing() { 94 // Explicitly flush and shutdown tracers 95 } 96 97 func Spanned(current context.Context, name string, 98 tracedFn func(context.Context) error) error { 99 newCtx, span := globalTracer.Start(current, name) 100 defer span.End() 101 102 err := tracedFn(newCtx) 103 if err != nil { 104 span.RecordError(err) 105 span.SetStatus(codes.Error, err.Error()) 106 } else { 107 span.SetStatus(codes.Ok, "") 108 } 109 110 return err 111 } 112 113 func SpannedT[T any](current context.Context, name string, tracedFn func(context.Context) (T, error)) (T, error) { 114 var ret T 115 var err error 116 117 err = Spanned(current, name, func(ctx context.Context) error { 118 ret, err = tracedFn(ctx) 119 return err 120 }) 121 122 return ret, err 123 } 124 125 func SetSpanAttribute(ctx context.Context, key string, value string) { 126 span := trace.SpanFromContext(ctx) 127 span.SetAttributes(attribute.KeyValue{ 128 Key: attribute.Key(key), 129 Value: attribute.StringValue(value), 130 }) 131 } 132 133 func LoggerTags(ctx context.Context) map[string]any { 134 tags := map[string]any{} 135 span := trace.SpanFromContext(ctx) 136 137 if span.IsRecording() { 138 tags["span_id"] = span.SpanContext().SpanID() 139 tags["trace_id"] = span.SpanContext().TraceID() 140 tags["trace_flags"] = span.SpanContext().TraceFlags() 141 } 142 143 return tags 144 } 145 146 func isTracingEnabled() bool { 147 bRet, err := strconv.ParseBool(os.Getenv(tracerControlEnvKey)) 148 if err != nil { 149 return false 150 } 151 152 return bRet 153 }