go-micro.dev/v5@v5.12.0/wrapper/trace/opentelemetry/wrapper.go (about) 1 package opentelemetry 2 3 import ( 4 "context" 5 "fmt" 6 7 "go-micro.dev/v5/client" 8 "go-micro.dev/v5/registry" 9 "go-micro.dev/v5/server" 10 "go.opentelemetry.io/otel/codes" 11 "go.opentelemetry.io/otel/trace" 12 ) 13 14 // NewCallWrapper accepts an opentracing Tracer and returns a Call Wrapper. 15 func NewCallWrapper(opts ...Option) client.CallWrapper { 16 options := Options{} 17 for _, o := range opts { 18 o(&options) 19 } 20 return func(cf client.CallFunc) client.CallFunc { 21 return func(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error { 22 if options.CallFilter != nil && options.CallFilter(ctx, req) { 23 return cf(ctx, node, req, rsp, opts) 24 } 25 name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) 26 spanOpts := []trace.SpanStartOption{ 27 trace.WithSpanKind(trace.SpanKindClient), 28 } 29 ctx, span := StartSpanFromContext(ctx, options.TraceProvider, name, spanOpts...) 30 defer span.End() 31 if err := cf(ctx, node, req, rsp, opts); err != nil { 32 span.SetStatus(codes.Error, err.Error()) 33 span.RecordError(err) 34 return err 35 } 36 return nil 37 } 38 } 39 } 40 41 // NewHandlerWrapper accepts an opentracing Tracer and returns a Handler Wrapper. 42 func NewHandlerWrapper(opts ...Option) server.HandlerWrapper { 43 options := Options{} 44 for _, o := range opts { 45 o(&options) 46 } 47 return func(h server.HandlerFunc) server.HandlerFunc { 48 return func(ctx context.Context, req server.Request, rsp interface{}) error { 49 if options.HandlerFilter != nil && options.HandlerFilter(ctx, req) { 50 return h(ctx, req, rsp) 51 } 52 name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) 53 spanOpts := []trace.SpanStartOption{ 54 trace.WithSpanKind(trace.SpanKindServer), 55 } 56 ctx, span := StartSpanFromContext(ctx, options.TraceProvider, name, spanOpts...) 57 defer span.End() 58 if err := h(ctx, req, rsp); err != nil { 59 span.SetStatus(codes.Error, err.Error()) 60 span.RecordError(err) 61 return err 62 } 63 return nil 64 } 65 } 66 } 67 68 // NewSubscriberWrapper accepts an opentracing Tracer and returns a Subscriber Wrapper. 69 func NewSubscriberWrapper(opts ...Option) server.SubscriberWrapper { 70 options := Options{} 71 for _, o := range opts { 72 o(&options) 73 } 74 return func(next server.SubscriberFunc) server.SubscriberFunc { 75 return func(ctx context.Context, msg server.Message) error { 76 if options.SubscriberFilter != nil && options.SubscriberFilter(ctx, msg) { 77 return next(ctx, msg) 78 } 79 name := "Sub from " + msg.Topic() 80 spanOpts := []trace.SpanStartOption{ 81 trace.WithSpanKind(trace.SpanKindServer), 82 } 83 ctx, span := StartSpanFromContext(ctx, options.TraceProvider, name, spanOpts...) 84 defer span.End() 85 if err := next(ctx, msg); err != nil { 86 span.SetStatus(codes.Error, err.Error()) 87 span.RecordError(err) 88 return err 89 } 90 return nil 91 } 92 } 93 } 94 95 // NewClientWrapper returns a client.Wrapper 96 // that adds monitoring to outgoing requests. 97 func NewClientWrapper(opts ...Option) client.Wrapper { 98 options := Options{} 99 for _, o := range opts { 100 o(&options) 101 } 102 return func(c client.Client) client.Client { 103 w := &clientWrapper{ 104 Client: c, 105 tp: options.TraceProvider, 106 callFilter: options.CallFilter, 107 streamFilter: options.StreamFilter, 108 publishFilter: options.PublishFilter, 109 } 110 return w 111 } 112 } 113 114 type clientWrapper struct { 115 client.Client 116 117 tp trace.TracerProvider 118 callFilter CallFilter 119 streamFilter StreamFilter 120 publishFilter PublishFilter 121 } 122 123 func (w *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { 124 if w.callFilter != nil && w.callFilter(ctx, req) { 125 return w.Client.Call(ctx, req, rsp, opts...) 126 } 127 name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) 128 spanOpts := []trace.SpanStartOption{ 129 trace.WithSpanKind(trace.SpanKindClient), 130 } 131 ctx, span := StartSpanFromContext(ctx, w.tp, name, spanOpts...) 132 defer span.End() 133 if err := w.Client.Call(ctx, req, rsp, opts...); err != nil { 134 span.SetStatus(codes.Error, err.Error()) 135 span.RecordError(err) 136 return err 137 } 138 return nil 139 } 140 141 func (w *clientWrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) { 142 if w.streamFilter != nil && w.streamFilter(ctx, req) { 143 return w.Client.Stream(ctx, req, opts...) 144 } 145 name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) 146 spanOpts := []trace.SpanStartOption{ 147 trace.WithSpanKind(trace.SpanKindClient), 148 } 149 ctx, span := StartSpanFromContext(ctx, w.tp, name, spanOpts...) 150 defer span.End() 151 stream, err := w.Client.Stream(ctx, req, opts...) 152 if err != nil { 153 span.SetStatus(codes.Error, err.Error()) 154 span.RecordError(err) 155 } 156 return stream, err 157 } 158 159 func (w *clientWrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error { 160 if w.publishFilter != nil && w.publishFilter(ctx, p) { 161 return w.Client.Publish(ctx, p, opts...) 162 } 163 name := fmt.Sprintf("Pub to %s", p.Topic()) 164 spanOpts := []trace.SpanStartOption{ 165 trace.WithSpanKind(trace.SpanKindClient), 166 } 167 ctx, span := StartSpanFromContext(ctx, w.tp, name, spanOpts...) 168 defer span.End() 169 if err := w.Client.Publish(ctx, p, opts...); err != nil { 170 span.SetStatus(codes.Error, err.Error()) 171 span.RecordError(err) 172 return err 173 } 174 return nil 175 }