2023-02-20 14:58:38 +00:00
|
|
|
package internal
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2023-08-23 12:52:47 +01:00
|
|
|
"encoding/base64"
|
2023-02-20 14:58:38 +00:00
|
|
|
"fmt"
|
2023-08-23 13:06:18 +01:00
|
|
|
"net/url"
|
2023-02-20 14:58:38 +00:00
|
|
|
"runtime/trace"
|
|
|
|
|
2023-09-13 16:58:44 +02:00
|
|
|
"go.opentelemetry.io/contrib/propagators/jaeger"
|
2023-02-20 14:58:38 +00:00
|
|
|
"go.opentelemetry.io/otel"
|
|
|
|
"go.opentelemetry.io/otel/attribute"
|
2023-08-23 12:52:47 +01:00
|
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
|
|
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
2023-02-21 10:50:39 +00:00
|
|
|
"go.opentelemetry.io/otel/propagation"
|
2023-02-20 17:55:34 +00:00
|
|
|
"go.opentelemetry.io/otel/sdk/resource"
|
|
|
|
tracesdk "go.opentelemetry.io/otel/sdk/trace"
|
|
|
|
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
|
2023-08-23 12:52:47 +01:00
|
|
|
otrace "go.opentelemetry.io/otel/trace"
|
2023-02-20 14:58:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const tracerName = "sliding-sync"
|
|
|
|
|
|
|
|
type TraceKey string
|
|
|
|
|
|
|
|
var (
|
2023-08-24 11:24:08 +01:00
|
|
|
OTLPTagDeviceID TraceKey = "device_id"
|
|
|
|
OTLPTagUserID TraceKey = "user_id"
|
|
|
|
OTLPTagConnID TraceKey = "conn_id"
|
|
|
|
OTLPTagTxnID TraceKey = "txn_id"
|
2023-02-20 14:58:38 +00:00
|
|
|
)
|
|
|
|
|
2023-08-24 11:24:08 +01:00
|
|
|
// SetAttributeOnContext sets one of the trace tag keys on the given context, so derived spans will use said tags.
|
|
|
|
func SetAttributeOnContext(ctx context.Context, key TraceKey, val string) context.Context {
|
|
|
|
return context.WithValue(ctx, key, val)
|
|
|
|
}
|
|
|
|
|
|
|
|
// attributesFromContext sets span tags based on data in the provided ctx
|
|
|
|
func attributesFromContext(ctx context.Context) []otrace.SpanStartOption {
|
|
|
|
var attrs []attribute.KeyValue
|
|
|
|
for _, tag := range []TraceKey{OTLPTagConnID, OTLPTagDeviceID, OTLPTagUserID, OTLPTagTxnID} {
|
|
|
|
val := ctx.Value(tag)
|
|
|
|
if val == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
attrs = append(attrs, attribute.String(string(tag), val.(string)))
|
|
|
|
}
|
|
|
|
if len(attrs) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return []otrace.SpanStartOption{
|
|
|
|
otrace.WithAttributes(attrs...),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 14:58:38 +00:00
|
|
|
type Task struct {
|
|
|
|
t *trace.Task
|
2023-08-23 12:52:47 +01:00
|
|
|
o otrace.Span
|
2023-02-20 14:58:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Task) End() {
|
|
|
|
s.t.End()
|
|
|
|
s.o.End()
|
|
|
|
}
|
|
|
|
|
|
|
|
// combined runtime/trace and OTLP span
|
|
|
|
type RuntimeTraceOTLPSpan struct {
|
|
|
|
region *trace.Region
|
2023-08-23 12:52:47 +01:00
|
|
|
span otrace.Span
|
2023-02-20 14:58:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RuntimeTraceOTLPSpan) End() {
|
|
|
|
s.region.End()
|
|
|
|
s.span.End()
|
|
|
|
}
|
|
|
|
|
|
|
|
func Logf(ctx context.Context, category, format string, args ...interface{}) {
|
|
|
|
trace.Logf(ctx, category, format, args...)
|
2023-08-23 12:52:47 +01:00
|
|
|
s := otrace.SpanFromContext(ctx)
|
|
|
|
s.AddEvent(fmt.Sprintf(format, args...), otrace.WithAttributes(
|
2023-02-20 14:58:38 +00:00
|
|
|
attribute.String("category", category),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
func StartSpan(ctx context.Context, name string) (newCtx context.Context, span *RuntimeTraceOTLPSpan) {
|
|
|
|
region := trace.StartRegion(ctx, name)
|
2023-08-24 11:24:08 +01:00
|
|
|
newCtx, ospan := otel.Tracer(tracerName).Start(ctx, name, attributesFromContext(ctx)...)
|
2023-02-20 14:58:38 +00:00
|
|
|
// use the same api as NewTask to allow context nesting
|
|
|
|
return newCtx, &RuntimeTraceOTLPSpan{
|
|
|
|
region: region,
|
|
|
|
span: ospan,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func StartTask(ctx context.Context, name string) (context.Context, *Task) {
|
|
|
|
ctx, task := trace.NewTask(ctx, name)
|
2023-08-24 11:24:08 +01:00
|
|
|
newCtx, ospan := otel.Tracer(tracerName).Start(ctx, name, attributesFromContext(ctx)...)
|
2023-02-20 14:58:38 +00:00
|
|
|
return newCtx, &Task{
|
|
|
|
t: task,
|
|
|
|
o: ospan,
|
|
|
|
}
|
|
|
|
}
|
2023-02-20 17:55:34 +00:00
|
|
|
|
2023-08-23 12:52:47 +01:00
|
|
|
func ConfigureOTLP(otlpURL, otlpUser, otlpPass, version string) error {
|
|
|
|
ctx := context.Background()
|
2023-08-23 13:06:18 +01:00
|
|
|
parsedOTLPURL, err := url.Parse(otlpURL)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
isInsecure := parsedOTLPURL.Scheme == "http" // e.g testing and development
|
|
|
|
if parsedOTLPURL.Path != "" {
|
|
|
|
return fmt.Errorf("OTLP URL %s cannot contain any path segments", otlpURL)
|
|
|
|
}
|
|
|
|
|
2023-08-23 12:52:47 +01:00
|
|
|
opts := []otlptracehttp.Option{
|
2023-08-23 13:06:18 +01:00
|
|
|
otlptracehttp.WithEndpoint(parsedOTLPURL.Host),
|
|
|
|
}
|
|
|
|
if isInsecure {
|
|
|
|
opts = append(opts, otlptracehttp.WithInsecure())
|
2023-08-23 12:52:47 +01:00
|
|
|
}
|
2023-08-23 15:38:45 +01:00
|
|
|
fmt.Println("ConfigureOTLP: host=", parsedOTLPURL.Host, "insecure=", isInsecure, "basic auth=", otlpPass != "" && otlpUser != "")
|
2023-08-23 12:52:47 +01:00
|
|
|
if otlpPass != "" && otlpUser != "" {
|
|
|
|
opts = append(opts, otlptracehttp.WithHeaders(
|
|
|
|
map[string]string{
|
|
|
|
"Authorization": fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", otlpUser, otlpPass)))),
|
|
|
|
},
|
|
|
|
))
|
|
|
|
}
|
|
|
|
client := otlptracehttp.NewClient(opts...)
|
|
|
|
// Create the OTLP exporter
|
|
|
|
exp, err := otlptrace.New(ctx, client)
|
2023-02-20 17:55:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
tp := tracesdk.NewTracerProvider(
|
|
|
|
// Always be sure to batch in production.
|
|
|
|
tracesdk.WithBatcher(exp),
|
|
|
|
// Record information about this application in a Resource.
|
|
|
|
tracesdk.WithResource(resource.NewWithAttributes(
|
|
|
|
semconv.SchemaURL,
|
|
|
|
semconv.ServiceName("sliding-sync"),
|
|
|
|
attribute.String("version", version),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
otel.SetTracerProvider(tp)
|
2023-02-21 10:50:39 +00:00
|
|
|
// setup traceparent (TraceContext) handling, and pass through any Baggage
|
|
|
|
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
|
2023-09-13 16:58:44 +02:00
|
|
|
propagation.Baggage{}, propagation.TraceContext{}, jaeger.Jaeger{},
|
2023-02-21 10:50:39 +00:00
|
|
|
))
|
2023-02-20 17:55:34 +00:00
|
|
|
return nil
|
|
|
|
}
|