Skip to content

Commit

Permalink
RFQ Guard: add prometheus metrics for disputes (#2894)
Browse files Browse the repository at this point in the history
* Feat: add otel recorder for guard

* Feat: call RecordDispute() before submitting tx

* [goreleaser]

* Fix: build

* [goreleaser]

* Feat: load disputes from db instead of cache

* [goreleaser]

* Fix: build

* [goreleaser]

* WIP: dispute logs

* [goreleaser]

* Revert "WIP: dispute logs"

This reverts commit 9607b99.

* Feat: add mux for metrics db query

---------

Co-authored-by: Trajan0x <[email protected]>
  • Loading branch information
dwasse and trajan0x authored Jul 28, 2024
1 parent 58df7a7 commit 9332b15
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
7 changes: 7 additions & 0 deletions services/rfq/guard/service/guard.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Guard struct {
chainListeners map[int]listener.ContractListener
contracts map[int]*fastbridge.FastBridgeRef
txSubmitter submitter.TransactionSubmitter
otelRecorder iOtelRecorder
}

// NewGuard creates a new Guard.
Expand Down Expand Up @@ -96,6 +97,11 @@ func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfi
txSubmitter = submitter.NewTransactionSubmitter(metricHandler, sg, omniClient, store.SubmitterDB(), &cfg.SubmitterConfig)
}

otelRecorder, err := newOtelRecorder(metricHandler, txSubmitter.Address(), store)
if err != nil {
return nil, fmt.Errorf("could not get otel recorder: %w", err)
}

return &Guard{
cfg: cfg,
metrics: metricHandler,
Expand All @@ -104,6 +110,7 @@ func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfi
chainListeners: chainListeners,
contracts: contracts,
txSubmitter: txSubmitter,
otelRecorder: otelRecorder,
}, nil
}

Expand Down
85 changes: 85 additions & 0 deletions services/rfq/guard/service/otel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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
}
7 changes: 7 additions & 0 deletions services/rfq/guard/service/otel_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9332b15

Please sign in to comment.