github.com/vseinstrumentiru/lego@v1.0.2/internal/lego/transport/event/metrics/subscriber.go (about) 1 package metrics 2 3 import ( 4 "emperror.dev/errors" 5 "github.com/ThreeDotsLabs/watermill/message" 6 "go.opencensus.io/stats" 7 "go.opencensus.io/tag" 8 ) 9 10 var ( 11 subscriberLabelKeys = []string{ 12 labelKeyHandlerName, 13 labelKeySubscriberName, 14 } 15 ) 16 17 type SubscriberDecorator struct { 18 message.Subscriber 19 subscriberName string 20 } 21 22 func (s *SubscriberDecorator) recordMetrics(msg *message.Message) { 23 if msg == nil { 24 return 25 } 26 27 ctx := msg.Context() 28 labels := labelsFromCtx(ctx, subscriberLabelKeys...) 29 30 if labels[labelKeySubscriberName] == "" { 31 labels[labelKeySubscriberName] = s.subscriberName 32 } 33 if labels[labelKeyHandlerName] == "" { 34 labels[labelKeyHandlerName] = labelValueNoHandler 35 } 36 37 tags := []tag.Mutator{ 38 tag.Upsert(SubscriberName, labels[labelKeySubscriberName]), 39 tag.Upsert(HandlerName, labels[labelKeyHandlerName]), 40 } 41 42 go func() { 43 if subscribeAlreadyObserved(ctx) { 44 // decorator idempotency when applied decorator multiple times 45 return 46 } 47 48 select { 49 case <-msg.Acked(): 50 tags = append(tags, tag.Upsert(Acked, "acked")) 51 case <-msg.Nacked(): 52 tags = append(tags, tag.Upsert(Acked, "nacked")) 53 } 54 55 _ = stats.RecordWithTags(ctx, tags, SubscriberReceivedMessage.M(1)) 56 }() 57 58 msg.SetContext(setSubscribeObservedToCtx(msg.Context())) 59 } 60 61 // DecorateSubscriber decorates a publisher with instrumentation. 62 func DecorateSubscriber(sub message.Subscriber) (message.Subscriber, error) { 63 d := &SubscriberDecorator{ 64 subscriberName: StructName(sub), 65 } 66 67 var err error 68 d.Subscriber, err = message.MessageTransformSubscriberDecorator(d.recordMetrics)(sub) 69 if err != nil { 70 return nil, errors.Wrap(err, "could not decorate subscriber with metrics decorator") 71 } 72 73 return d, nil 74 }