diff --git a/pkg/workflows/dontime/metrics.go b/pkg/workflows/dontime/metrics.go new file mode 100644 index 000000000..e7926ff64 --- /dev/null +++ b/pkg/workflows/dontime/metrics.go @@ -0,0 +1,49 @@ +package dontime + +import ( + "context" + "fmt" + "github.com/smartcontractkit/chainlink-common/pkg/beholder" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + promDONTimeClockDrift = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "don_time_clock_drift_ms", + Help: "Drift between node local time and generated DON Time", + }, []string{"oracleID"}) +) + +type GenericDONTimeMetrics interface { + RecordClockDrift(ctx context.Context, drift int64) +} + +var _ GenericDONTimeMetrics = &donTimeMetrics{} + +type donTimeMetrics struct { + oracleID string + donTimeCount metric.Int64Counter + clockDrift metric.Int64Gauge +} + +func NewGenericDONTimeMetrics(oracleID string) (GenericDONTimeMetrics, error) { + clockDrift, err := beholder.GetMeter().Int64Gauge("don_time_clock_drift_ms") + if err != nil { + return nil, fmt.Errorf("failed to register clock drift metric: %w", err) + } + + return &donTimeMetrics{ + oracleID: oracleID, + clockDrift: clockDrift, + }, nil +} + +func (m *donTimeMetrics) RecordClockDrift(ctx context.Context, drift int64) { + promDONTimeClockDrift.WithLabelValues(m.oracleID).Set(float64(drift)) + m.clockDrift.Record(ctx, drift, metric.WithAttributes( + attribute.String("oracleID", m.oracleID))) +} diff --git a/pkg/workflows/dontime/plugin.go b/pkg/workflows/dontime/plugin.go index ece80d7dd..0408ae0e5 100644 --- a/pkg/workflows/dontime/plugin.go +++ b/pkg/workflows/dontime/plugin.go @@ -22,6 +22,7 @@ import ( type Plugin struct { mu sync.RWMutex + metrics GenericDONTimeMetrics store *Store config ocr3types.ReportingPluginConfig offChainConfig *pb.Config @@ -49,7 +50,13 @@ func NewPlugin(store *Store, config ocr3types.ReportingPluginConfig, lggr logger return nil, errors.New("execution removal time must be positive") } + metrics, err := NewGenericDONTimeMetrics(string(config.OracleID)) + if err != nil { + return nil, fmt.Errorf("failed to register DON Time metrics: %w", err) + } + return &Plugin{ + metrics: metrics, store: store, config: config, offChainConfig: offchainCfg, @@ -168,7 +175,12 @@ func (p *Plugin) Outcome(_ context.Context, outctx ocr3types.OutcomeContext, _ t donTime = outcome.Timestamp + p.minTimeIncrease } - p.lggr.Infow("New DON Time", "donTime", donTime) + driftMs := time.Now().UTC().UnixMilli() - donTime + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + p.metrics.RecordClockDrift(ctx, driftMs) + p.lggr.Infow("New DON Time", "donTime", donTime, "clockDriftMs", driftMs) + outcome.Timestamp = donTime for id, numRequests := range observationCounts {