Skip to content

Commit c8651a4

Browse files
chore(metrics): dual-export OCR2 transmit metrics via OpenTelemetry
Record confirmed/reverted/fatal counters and unconfirmed gauge via beholder alongside Prometheus; pass context into RecordOutcome (DF-21989).
1 parent 472b479 commit c8651a4

4 files changed

Lines changed: 87 additions & 8 deletions

File tree

pkg/ocr2transmit/metrics.go

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package ocr2transmit
22

33
import (
4+
"context"
45
"math/big"
6+
"sync"
57

68
"github.com/ethereum/go-ethereum/common"
79
"github.com/prometheus/client_golang/prometheus"
810
"github.com/prometheus/client_golang/prometheus/promauto"
11+
"go.opentelemetry.io/otel/attribute"
12+
"go.opentelemetry.io/otel/metric"
13+
14+
"github.com/smartcontractkit/chainlink-common/pkg/beholder"
915
)
1016

1117
var (
@@ -27,8 +33,64 @@ var (
2733
}, []string{"chain_id", "from_address"})
2834
)
2935

36+
type ocr2TransmitOtelInstruments struct {
37+
confirmed metric.Int64Counter
38+
reverted metric.Int64Counter
39+
fatal metric.Int64Counter
40+
unconfirmed metric.Int64Gauge
41+
}
42+
43+
var (
44+
ocr2TransmitOtelInst *ocr2TransmitOtelInstruments
45+
ocr2TransmitOtelOnce sync.Once
46+
)
47+
48+
func loadOCR2TransmitOtel() *ocr2TransmitOtelInstruments {
49+
ocr2TransmitOtelOnce.Do(func() {
50+
m := beholder.GetMeter()
51+
confirmed, err := m.Int64Counter("ocr2_transmit_tx_confirmed_total")
52+
if err != nil {
53+
return
54+
}
55+
reverted, err := m.Int64Counter("ocr2_transmit_tx_reverted_total")
56+
if err != nil {
57+
return
58+
}
59+
fatal, err := m.Int64Counter("ocr2_transmit_tx_fatal_total")
60+
if err != nil {
61+
return
62+
}
63+
unconfirmed, err := m.Int64Gauge("ocr2_transmit_unconfirmed_tx_count")
64+
if err != nil {
65+
return
66+
}
67+
ocr2TransmitOtelInst = &ocr2TransmitOtelInstruments{
68+
confirmed: confirmed,
69+
reverted: reverted,
70+
fatal: fatal,
71+
unconfirmed: unconfirmed,
72+
}
73+
})
74+
return ocr2TransmitOtelInst
75+
}
76+
77+
func transmitAttrs(chainID *big.Int, contract, from string) metric.MeasurementOption {
78+
return metric.WithAttributes(
79+
attribute.String("chain_id", chainID.String()),
80+
attribute.String("contract_address", contract),
81+
attribute.String("from_address", from),
82+
)
83+
}
84+
85+
func unconfirmedAttrs(chainID *big.Int, from string) metric.MeasurementOption {
86+
return metric.WithAttributes(
87+
attribute.String("chain_id", chainID.String()),
88+
attribute.String("from_address", from),
89+
)
90+
}
91+
3092
// RecordOutcome increments confirmed / reverted / fatal counters when calldata matches OCR2 transmit.
31-
func RecordOutcome(chainID *big.Int, from, to common.Address, encodedPayload []byte, fwdrDest *common.Address, outcome string) {
93+
func RecordOutcome(ctx context.Context, chainID *big.Int, from, to common.Address, encodedPayload []byte, fwdrDest *common.Address, outcome string) {
3294
if chainID == nil || !IsTransmitCalldata(encodedPayload) {
3395
return
3496
}
@@ -41,13 +103,29 @@ func RecordOutcome(chainID *big.Int, from, to common.Address, encodedPayload []b
41103
promTransmitReverted.WithLabelValues(labels...).Inc()
42104
case "fatal":
43105
promTransmitFatal.WithLabelValues(labels...).Inc()
106+
default:
107+
return
108+
}
109+
if ot := loadOCR2TransmitOtel(); ot != nil {
110+
opts := transmitAttrs(chainID, contract, from.Hex())
111+
switch outcome {
112+
case "confirmed":
113+
ot.confirmed.Add(ctx, 1, opts)
114+
case "reverted":
115+
ot.reverted.Add(ctx, 1, opts)
116+
case "fatal":
117+
ot.fatal.Add(ctx, 1, opts)
118+
}
44119
}
45120
}
46121

47122
// SetUnconfirmedGauge sets the gauge for OCR2-shaped unconfirmed txs for TXM v2 (optional / phase 3).
48-
func SetUnconfirmedGauge(chainID *big.Int, from common.Address, n int) {
123+
func SetUnconfirmedGauge(ctx context.Context, chainID *big.Int, from common.Address, n int) {
49124
if chainID == nil {
50125
return
51126
}
52127
promTransmitUnconfirmed.WithLabelValues(chainID.String(), from.Hex()).Set(float64(n))
128+
if ot := loadOCR2TransmitOtel(); ot != nil {
129+
ot.unconfirmed.Record(ctx, int64(n), unconfirmedAttrs(chainID, from.Hex()))
130+
}
53131
}

pkg/txm/txm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ func (t *Txm) extractMetrics(ctx context.Context, txs []*types.Transaction) []ui
448448
if meta, err := tx.GetMeta(); err == nil && meta != nil && meta.FwdrDestAddress != nil {
449449
fwdr = meta.FwdrDestAddress
450450
}
451-
ocr2transmit.RecordOutcome(t.chainID, tx.FromAddress, tx.ToAddress, tx.Data, fwdr, "confirmed")
451+
ocr2transmit.RecordOutcome(ctx, t.chainID, tx.FromAddress, tx.ToAddress, tx.Data, fwdr, "confirmed")
452452
}
453453
return confirmedTxIDs
454454
}

pkg/txmgr/finalizer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -504,10 +504,10 @@ func (f *evmFinalizer) validateReceipt(ctx context.Context, receipt *types.Recei
504504
}
505505
// This might increment more than once e.g. in case of re-orgs going back and forth we might re-fetch the same receipt
506506
f.metrics.IncrementNumRevertedTxs(ctx)
507-
recordOCR2TransmitOutcomeV1(f.chainID, &attempt.Tx, "reverted")
507+
recordOCR2TransmitOutcomeV1(ctx, f.chainID, &attempt.Tx, "reverted")
508508
} else {
509509
f.metrics.IncrementNumSuccessfulTxs(ctx)
510-
recordOCR2TransmitOutcomeV1(f.chainID, &attempt.Tx, "confirmed")
510+
recordOCR2TransmitOutcomeV1(ctx, f.chainID, &attempt.Tx, "confirmed")
511511
}
512512

513513
// This is only recording forwarded tx that were mined and have a status.
@@ -603,7 +603,7 @@ func (f *evmFinalizer) ProcessOldTxsWithoutReceipts(ctx context.Context, oldTxID
603603
if err = f.txStore.UpdateTxFatalErrorAndDeleteAttempts(ctx, oldTx); err != nil {
604604
errorList = append(errorList, fmt.Errorf("failed to mark tx with ID %d as fatal: %w", oldTx.ID, err))
605605
} else {
606-
recordOCR2TransmitOutcomeV1(f.chainID, oldTx, "fatal")
606+
recordOCR2TransmitOutcomeV1(ctx, f.chainID, oldTx, "fatal")
607607
}
608608
}
609609
if len(errorList) > 0 {

pkg/txmgr/ocr2_transmit_metrics.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package txmgr
22

33
import (
4+
"context"
45
"math/big"
56

67
"github.com/ethereum/go-ethereum/common"
78

89
"github.com/smartcontractkit/chainlink-evm/pkg/ocr2transmit"
910
)
1011

11-
func recordOCR2TransmitOutcomeV1(chainID *big.Int, tx *Tx, outcome string) {
12+
func recordOCR2TransmitOutcomeV1(ctx context.Context, chainID *big.Int, tx *Tx, outcome string) {
1213
if tx == nil {
1314
return
1415
}
@@ -20,5 +21,5 @@ func recordOCR2TransmitOutcomeV1(chainID *big.Int, tx *Tx, outcome string) {
2021
if cid == nil {
2122
cid = tx.ChainID
2223
}
23-
ocr2transmit.RecordOutcome(cid, tx.FromAddress, tx.ToAddress, tx.EncodedPayload, fwdr, outcome)
24+
ocr2transmit.RecordOutcome(ctx, cid, tx.FromAddress, tx.ToAddress, tx.EncodedPayload, fwdr, outcome)
2425
}

0 commit comments

Comments
 (0)