@@ -2,19 +2,25 @@ package beholder
22
33import (
44 "context"
5+ "errors"
56 "fmt"
7+ "sync/atomic"
68
79 "github.com/smartcontractkit/chainlink-common/pkg/logger"
10+ "github.com/smartcontractkit/chainlink-common/pkg/services"
811)
912
10- // dualSourceEmitter emits both to chip ingress and to the otel collector
13+ // DualSourceEmitter emits both to chip ingress and to the otel collector
1114// this is to help transition from sending custom messages via OTLP to instead use chip-ingress
1215// we want to send to both during the transition period, then cutover to using
1316// chipIngressEmitter only
1417type DualSourceEmitter struct {
1518 chipIngressEmitter Emitter
1619 otelCollectorEmitter Emitter
1720 log logger.Logger
21+ stopCh services.StopChan
22+ wg services.WaitGroup
23+ closed atomic.Bool
1824}
1925
2026func NewDualSourceEmitter (chipIngressEmitter Emitter , otelCollectorEmitter Emitter ) (Emitter , error ) {
@@ -36,9 +42,19 @@ func NewDualSourceEmitter(chipIngressEmitter Emitter, otelCollectorEmitter Emitt
3642 chipIngressEmitter : chipIngressEmitter ,
3743 otelCollectorEmitter : otelCollectorEmitter ,
3844 log : logger ,
45+ stopCh : make (services.StopChan ),
3946 }, nil
4047}
4148
49+ func (d * DualSourceEmitter ) Close () error {
50+ if wasClosed := d .closed .Swap (true ); wasClosed {
51+ return errors .New ("already closed" )
52+ }
53+ close (d .stopCh )
54+ d .wg .Wait ()
55+ return errors .Join (d .chipIngressEmitter .Close (), d .otelCollectorEmitter .Close ())
56+ }
57+
4258func (d * DualSourceEmitter ) Emit (ctx context.Context , body []byte , attrKVs ... any ) error {
4359
4460 // Emit via OTLP first
@@ -47,13 +63,21 @@ func (d *DualSourceEmitter) Emit(ctx context.Context, body []byte, attrKVs ...an
4763 }
4864
4965 // Emit via chip ingress async
50- go func () {
51- if err := d .chipIngressEmitter .Emit (context .WithoutCancel (ctx ), body , attrKVs ... ); err != nil {
66+ if err := d .wg .TryAdd (1 ); err != nil {
67+ return err
68+ }
69+ go func (ctx context.Context ) {
70+ defer d .wg .Done ()
71+ var cancel context.CancelFunc
72+ ctx , cancel = d .stopCh .Ctx (ctx )
73+ defer cancel ()
74+
75+ if err := d .chipIngressEmitter .Emit (ctx , body , attrKVs ... ); err != nil {
5276 // If the chip ingress emitter fails, we ONLY log the error
5377 // because we still want to send the data to the OTLP collector and not cause disruption
5478 d .log .Infof ("failed to emit to chip ingress: %v" , err )
5579 }
56- }()
80+ }(context . WithoutCancel ( ctx ) )
5781
5882 return nil
5983}
0 commit comments