github.com/zly-app/zapp@v1.3.3/pkg/utils/otel.go (about) 1 package utils 2 3 import ( 4 "context" 5 "net/http" 6 "time" 7 8 "github.com/spf13/cast" 9 "go.opentelemetry.io/otel" 10 "go.opentelemetry.io/otel/attribute" 11 "go.opentelemetry.io/otel/codes" 12 "go.opentelemetry.io/otel/propagation" 13 "go.opentelemetry.io/otel/trace" 14 ) 15 16 var Otel = &otelCli{} 17 18 type otelCli struct{} 19 20 // key, 示例 OtelSpanKey("foo").String("bar") 21 type OtelSpanKey = attribute.Key 22 type OtelSpanKV = attribute.KeyValue 23 24 func (*otelCli) GlobalTrace(name string) trace.Tracer { 25 return otel.Tracer(name) 26 } 27 28 // 将span存入ctx中 29 func (*otelCli) SaveSpan(ctx context.Context, span trace.Span) context.Context { 30 return trace.ContextWithSpan(ctx, span) 31 } 32 33 // 将span存入ctx中 34 // Deprecated: use SaveSpan 35 func (*otelCli) SaveToContext(ctx context.Context, span trace.Span) context.Context { 36 return trace.ContextWithSpan(ctx, span) 37 } 38 39 // 从ctx中获取span 40 func (*otelCli) GetSpan(ctx context.Context) trace.Span { 41 return trace.SpanFromContext(ctx) 42 } 43 44 func (*otelCli) SaveToHeaders(ctx context.Context, headers http.Header) { 45 v := propagation.HeaderCarrier(headers) 46 otel.GetTextMapPropagator().Inject(ctx, v) 47 } 48 49 func (c *otelCli) GetSpanWithHeaders(ctx context.Context, headers http.Header) (context.Context, trace.Span) { 50 v := propagation.HeaderCarrier(headers) 51 ctx = otel.GetTextMapPropagator().Extract(ctx, v) 52 return ctx, c.GetSpan(ctx) 53 } 54 55 func (*otelCli) SaveToMap(ctx context.Context, mapping map[string]string) { 56 v := propagation.MapCarrier(mapping) 57 otel.GetTextMapPropagator().Inject(ctx, v) 58 } 59 60 func (c *otelCli) GetSpanWithMap(ctx context.Context, mapping map[string]string) (context.Context, trace.Span) { 61 v := propagation.MapCarrier(mapping) 62 ctx = otel.GetTextMapPropagator().Extract(ctx, v) 63 return ctx, c.GetSpan(ctx) 64 } 65 66 func (*otelCli) SaveToTextMapCarrier(ctx context.Context, carrier propagation.TextMapCarrier) { 67 otel.GetTextMapPropagator().Inject(ctx, carrier) 68 } 69 70 func (c *otelCli) GetSpanWithTextMapCarrier(ctx context.Context, carrier propagation.TextMapCarrier) (context.Context, trace.Span) { 71 ctx = otel.GetTextMapPropagator().Extract(ctx, carrier) 72 return ctx, c.GetSpan(ctx) 73 } 74 75 // 开始一个span 76 func (*otelCli) StartSpan(ctx context.Context, spanName string, attributes ...OtelSpanKV) ( 77 context.Context, trace.Span) { 78 return otel.Tracer("").Start(ctx, spanName, trace.WithAttributes(attributes...)) 79 } 80 81 // 设置span属性. 属性是作为元数据应用于跨度的键和值,可用于聚合、过滤和分组跟踪 82 func (*otelCli) SetSpanAttributes(span trace.Span, attributes ...OtelSpanKV) { 83 span.SetAttributes(attributes...) 84 } 85 86 // 添加事件, 事件的属性不会用于聚合、过滤和分组跟踪 87 func (*otelCli) AddSpanEvent(span trace.Span, eventName string, attributes ...OtelSpanKV) { 88 span.AddEvent(eventName, trace.WithAttributes(attributes...)) 89 } 90 91 // 将span标记为错误 92 func (*otelCli) MarkSpanAnError(span trace.Span, isErr bool) { 93 span.SetStatus(codes.Error, cast.ToString(isErr)) 94 } 95 96 // 结束一个span 97 func (*otelCli) EndSpan(span trace.Span) { 98 span.End() 99 } 100 101 // 获取 traceID 102 func (*otelCli) GetOTELTraceID(ctx context.Context) (traceID string, spanID string) { 103 sc := trace.SpanContextFromContext(ctx) 104 return sc.TraceID().String(), sc.SpanID().String() 105 } 106 107 // 根据超时ctx获取一个OtelSpanKV描述 108 func (*otelCli) GetSpanKVWithDeadline(ctx context.Context) OtelSpanKV { 109 deadline, deadlineOK := ctx.Deadline() 110 if !deadlineOK { 111 return OtelSpanKey("ctx.deadline").Bool(false) 112 } 113 d := deadline.Sub(time.Now()) // 剩余时间 114 return OtelSpanKey("ctx.deadline").String(d.String()) 115 } 116 117 // 创建一个OtelSpanKV描述 118 func (*otelCli) AttrKey(key string) OtelSpanKey { 119 return OtelSpanKey(key) 120 } 121 122 func (c *otelCli) CtxStart(ctx context.Context, name string, attributes ...OtelSpanKV) context.Context { 123 // 生成新的 span 124 ctx, _ = c.StartSpan(ctx, name, attributes...) 125 return ctx 126 } 127 128 func (c *otelCli) CtxEvent(ctx context.Context, name string, attributes ...OtelSpanKV) { 129 span := c.GetSpan(ctx) 130 attr := []OtelSpanKV{ 131 c.GetSpanKVWithDeadline(ctx), 132 } 133 attr = append(attr, attributes...) 134 c.AddSpanEvent(span, name, attr...) 135 } 136 137 func (c *otelCli) CtxErrEvent(ctx context.Context, name string, err error, attributes ...OtelSpanKV) { 138 span := c.GetSpan(ctx) 139 attr := []OtelSpanKV{ 140 c.GetSpanKVWithDeadline(ctx), 141 OtelSpanKey("err.detail").String(err.Error()), 142 } 143 if Recover.IsRecoverError(err) { 144 c.SetSpanAttributes(span, OtelSpanKey("panic").Bool(true)) 145 panicErrs := Recover.GetRecoverErrors(err) 146 attr = append(attr, OtelSpanKey("detail").StringSlice(panicErrs)) 147 } 148 149 attr = append(attr, attributes...) 150 c.AddSpanEvent(span, name+" err", attr...) 151 c.MarkSpanAnError(span, true) 152 } 153 154 func (c *otelCli) CtxEnd(ctx context.Context) { 155 span := c.GetSpan(ctx) 156 c.EndSpan(span) 157 }