package service import ( "context" "fmt" "sync" "github.com/ethereum/go-ethereum/common" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/services/rfq/guard/guarddb" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" ) const meterName = "github.com/synapsecns/sanguine/services/rfq/guard/service" // generate an interface for otelRecorder that exports the public method. // this allows us to avoid using recordX externally anad makes the package less confusing. // // ============================================================================= // ============================================================================= // IMPORTANT: DO NOT REMOVE THIS COMMENT. // NOTICE: PLEASE MAKE SURE YOU UPDATE BOTH THE DOCS AND THE GRAFANA DASHBOARD (IF NEEDED) AFTER UPDATING METRICS. // ============================================================================= // ============================================================================= // //go:generate go run github.com/vburenin/ifacemaker -f otel.go -s otelRecorder -i iOtelRecorder -p service -o otel_generated.go -c "autogenerated file" type otelRecorder struct { metrics metrics.Handler // meter is the metrics meter. meter metric.Meter // disputeGauge is the gauge for the disputeCounts. disputeGauge metric.Int64ObservableGauge // db is a database connection for fetching disputes. db guarddb.Service // walletAddress is the wallet address for the signer. walletAddress common.Address // mux is a mutex used for making sure only one db query is run at a time. mux sync.Mutex } func newOtelRecorder(meterHandler metrics.Handler, walletAddress common.Address, db guarddb.Service) (_ iOtelRecorder, err error) { or := otelRecorder{ metrics: meterHandler, meter: meterHandler.Meter(meterName), db: db, walletAddress: walletAddress, } or.disputeGauge, err = or.meter.Int64ObservableGauge("dispute_count") if err != nil { return nil, fmt.Errorf("could not create dispute count gauge: %w", err) } _, err = or.meter.RegisterCallback(or.recordDisputeCounts, or.disputeGauge) if err != nil { return nil, fmt.Errorf("could not register callback for dispute count gauge: %w", err) } return &or, nil } func (o *otelRecorder) recordDisputeCounts(ctx context.Context, observer metric.Observer) (err error) { if o.metrics == nil || o.disputeGauge == nil || o.db == nil { return nil } // make sure we aren't making simultaneous db queries if o.mux.TryLock() { defer o.mux.Unlock() } else { return nil } results, err := o.db.GetPendingProvensByStatus(ctx, guarddb.DisputePending, guarddb.Disputed) if err != nil { return fmt.Errorf("could not get disputes: %w", err) } opts := metric.WithAttributes( attribute.String("wallet", o.walletAddress.Hex()), ) observer.ObserveInt64(o.disputeGauge, int64(len(results)), opts) return nil }