Commit bdb8de13 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Merge pull request #2235 from cfromknecht/bsscore-iface-metrics

interface bss-core metrics to allow for driver-specific metrics extensions
parents dde4543e 87359fd2
---
'@eth-optimism/batch-submitter-service': patch
---
Refactors the bss-core service to use a metrics interface to allow
driver-specific metric extensions
...@@ -45,7 +45,7 @@ type Driver struct { ...@@ -45,7 +45,7 @@ type Driver struct {
rawSccContract *bind.BoundContract rawSccContract *bind.BoundContract
ctcContract *ctc.CanonicalTransactionChain ctcContract *ctc.CanonicalTransactionChain
walletAddr common.Address walletAddr common.Address
metrics *metrics.Metrics metrics *metrics.Base
} }
func NewDriver(cfg Config) (*Driver, error) { func NewDriver(cfg Config) (*Driver, error) {
...@@ -82,7 +82,7 @@ func NewDriver(cfg Config) (*Driver, error) { ...@@ -82,7 +82,7 @@ func NewDriver(cfg Config) (*Driver, error) {
rawSccContract: rawSccContract, rawSccContract: rawSccContract,
ctcContract: ctcContract, ctcContract: ctcContract,
walletAddr: walletAddr, walletAddr: walletAddr,
metrics: metrics.NewMetrics(cfg.Name), metrics: metrics.NewBase("batch_submitter", cfg.Name),
}, nil }, nil
} }
...@@ -97,7 +97,7 @@ func (d *Driver) WalletAddr() common.Address { ...@@ -97,7 +97,7 @@ func (d *Driver) WalletAddr() common.Address {
} }
// Metrics returns the subservice telemetry object. // Metrics returns the subservice telemetry object.
func (d *Driver) Metrics() *metrics.Metrics { func (d *Driver) Metrics() metrics.Metrics {
return d.metrics return d.metrics
} }
...@@ -184,7 +184,7 @@ func (d *Driver) CraftBatchTx( ...@@ -184,7 +184,7 @@ func (d *Driver) CraftBatchTx(
stateRoots = append(stateRoots, block.Root()) stateRoots = append(stateRoots, block.Root())
} }
d.metrics.NumElementsPerBatch.Observe(float64(len(stateRoots))) d.metrics.NumElementsPerBatch().Observe(float64(len(stateRoots)))
log.Info(name+" batch constructed", "num_state_roots", len(stateRoots)) log.Info(name+" batch constructed", "num_state_roots", len(stateRoots))
......
...@@ -44,7 +44,7 @@ type Driver struct { ...@@ -44,7 +44,7 @@ type Driver struct {
rawCtcContract *bind.BoundContract rawCtcContract *bind.BoundContract
walletAddr common.Address walletAddr common.Address
ctcABI *abi.ABI ctcABI *abi.ABI
metrics *metrics.Metrics metrics *Metrics
} }
func NewDriver(cfg Config) (*Driver, error) { func NewDriver(cfg Config) (*Driver, error) {
...@@ -80,7 +80,7 @@ func NewDriver(cfg Config) (*Driver, error) { ...@@ -80,7 +80,7 @@ func NewDriver(cfg Config) (*Driver, error) {
rawCtcContract: rawCtcContract, rawCtcContract: rawCtcContract,
walletAddr: walletAddr, walletAddr: walletAddr,
ctcABI: ctcABI, ctcABI: ctcABI,
metrics: metrics.NewMetrics(cfg.Name), metrics: NewMetrics(cfg.Name),
}, nil }, nil
} }
...@@ -95,7 +95,7 @@ func (d *Driver) WalletAddr() common.Address { ...@@ -95,7 +95,7 @@ func (d *Driver) WalletAddr() common.Address {
} }
// Metrics returns the subservice telemetry object. // Metrics returns the subservice telemetry object.
func (d *Driver) Metrics() *metrics.Metrics { func (d *Driver) Metrics() metrics.Metrics {
return d.metrics return d.metrics
} }
...@@ -219,7 +219,7 @@ func (d *Driver) CraftBatchTx( ...@@ -219,7 +219,7 @@ func (d *Driver) CraftBatchTx(
continue continue
} }
d.metrics.NumElementsPerBatch.Observe(float64(len(batchElements))) d.metrics.NumElementsPerBatch().Observe(float64(len(batchElements)))
d.metrics.BatchPruneCount.Set(float64(pruneCount)) d.metrics.BatchPruneCount.Set(float64(pruneCount))
log.Info(name+" batch constructed", "num_txs", len(batchElements), "length", len(batchCallData)) log.Info(name+" batch constructed", "num_txs", len(batchElements), "length", len(batchCallData))
......
package sequencer
import (
"github.com/ethereum-optimism/optimism/go/bss-core/metrics"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
// Metrics extends the BSS core metrics with additional metrics tracked by the
// sequencer driver.
type Metrics struct {
*metrics.Base
// BatchPruneCount tracks the number of times a batch of sequencer
// transactions is pruned in order to meet the desired size requirements.
BatchPruneCount prometheus.Gauge
}
// NewMetrics initializes a new, extended metrics object.
func NewMetrics(subsystem string) *Metrics {
base := metrics.NewBase("batch_submitter", subsystem)
return &Metrics{
Base: base,
BatchPruneCount: promauto.NewGauge(prometheus.GaugeOpts{
Name: "batch_prune_count",
Help: "Number of times a batch is pruned",
Subsystem: base.SubsystemName(),
}),
}
}
...@@ -7,6 +7,7 @@ require ( ...@@ -7,6 +7,7 @@ require (
github.com/ethereum-optimism/optimism/l2geth v1.0.0 github.com/ethereum-optimism/optimism/l2geth v1.0.0
github.com/ethereum/go-ethereum v1.10.16 github.com/ethereum/go-ethereum v1.10.16
github.com/getsentry/sentry-go v0.11.0 github.com/getsentry/sentry-go v0.11.0
github.com/prometheus/client_golang v1.11.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/urfave/cli v1.22.5 github.com/urfave/cli v1.22.5
) )
......
package metrics
import "github.com/prometheus/client_golang/prometheus"
type Metrics interface {
// SubsystemName returns the subsystem name for the metrics group.
SubsystemName() string
// BalanceETH tracks the amount of ETH in the submitter's account.
BalanceETH() prometheus.Gauge
// BatchSizeBytes tracks the size of batch submission transactions.
BatchSizeBytes() prometheus.Summary
// NumElementsPerBatch tracks the number of L2 transactions in each batch
// submission.
NumElementsPerBatch() prometheus.Summary
// SubmissionTimestamp tracks the time at which each batch was confirmed.
SubmissionTimestamp() prometheus.Gauge
// SubmissionGasUsedWei tracks the amount of gas used to submit each batch.
SubmissionGasUsedWei() prometheus.Gauge
// BatchsSubmitted tracks the total number of successful batch submissions.
BatchesSubmitted() prometheus.Counter
// FailedSubmissions tracks the total number of failed batch submissions.
FailedSubmissions() prometheus.Counter
// BatchTxBuildTimeMs tracks the duration it takes to construct a batch
// transaction.
BatchTxBuildTimeMs() prometheus.Gauge
// BatchConfirmationTimeMs tracks the duration it takes to confirm a batch
// transaction.
BatchConfirmationTimeMs() prometheus.Gauge
}
package metrics package metrics
import ( import (
"fmt"
"strings" "strings"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
) )
type Metrics struct { type Base struct {
// ETHBalance tracks the amount of ETH in the submitter's account. // subsystemName stores the name that will prefix all metrics. This can be
ETHBalance prometheus.Gauge // used by drivers to futher extend the core metrics and ensure they use the
// same prefix.
subsystemName string
// BatchSizeInBytes tracks the size of batch submission transactions. // balanceETH tracks the amount of ETH in the submitter's account.
BatchSizeInBytes prometheus.Summary balanceETH prometheus.Gauge
// NumElementsPerBatch tracks the number of L2 transactions in each batch // batchSizeBytes tracks the size of batch submission transactions.
batchSizeBytes prometheus.Summary
// numElementsPerBatch tracks the number of L2 transactions in each batch
// submission. // submission.
NumElementsPerBatch prometheus.Summary numElementsPerBatch prometheus.Summary
// SubmissionTimestamp tracks the time at which each batch was confirmed. // submissionTimestamp tracks the time at which each batch was confirmed.
SubmissionTimestamp prometheus.Gauge submissionTimestamp prometheus.Gauge
// SubmissionGasUsed tracks the amount of gas used to submit each batch. // submissionGasUsedWei tracks the amount of gas used to submit each batch.
SubmissionGasUsed prometheus.Gauge submissionGasUsedWei prometheus.Gauge
// BatchsSubmitted tracks the total number of successful batch submissions. // batchsSubmitted tracks the total number of successful batch submissions.
BatchesSubmitted prometheus.Counter batchesSubmitted prometheus.Counter
// FailedSubmissions tracks the total number of failed batch submissions. // failedSubmissions tracks the total number of failed batch submissions.
FailedSubmissions prometheus.Counter failedSubmissions prometheus.Counter
// BatchTxBuildTime tracks the duration it takes to construct a batch // batchTxBuildTimeMs tracks the duration it takes to construct a batch
// transaction. // transaction.
BatchTxBuildTime prometheus.Gauge batchTxBuildTimeMs prometheus.Gauge
// BatchConfirmationTime tracks the duration it takes to confirm a batch // batchConfirmationTimeMs tracks the duration it takes to confirm a batch
// transaction. // transaction.
BatchConfirmationTime prometheus.Gauge batchConfirmationTimeMs prometheus.Gauge
// BatchPruneCount tracks the number of times a batch of sequencer
// transactions is pruned in order to meet the desired size requirements.
//
// NOTE: This is currently only active in the sequencer driver.
BatchPruneCount prometheus.Gauge
} }
func NewMetrics(subsystem string) *Metrics { func NewBase(serviceName, subServiceName string) *Base {
subsystem = "batch_submitter_" + strings.ToLower(subsystem) subsystem := MakeSubsystemName(serviceName, subServiceName)
return &Metrics{ return &Base{
ETHBalance: promauto.NewGauge(prometheus.GaugeOpts{ subsystemName: subsystem,
balanceETH: promauto.NewGauge(prometheus.GaugeOpts{
Name: "balance_eth", Name: "balance_eth",
Help: "ETH balance of the batch submitter", Help: "ETH balance of the batch submitter",
Subsystem: subsystem, Subsystem: subsystem,
}), }),
BatchSizeInBytes: promauto.NewSummary(prometheus.SummaryOpts{ batchSizeBytes: promauto.NewSummary(prometheus.SummaryOpts{
Name: "batch_size_bytes", Name: "batch_size_bytes",
Help: "Size of batches in bytes", Help: "Size of batches in bytes",
Subsystem: subsystem, Subsystem: subsystem,
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
}), }),
NumElementsPerBatch: promauto.NewSummary(prometheus.SummaryOpts{ numElementsPerBatch: promauto.NewSummary(prometheus.SummaryOpts{
Name: "num_elements_per_batch", Name: "num_elements_per_batch",
Help: "Number of elements in each batch", Help: "Number of elements in each batch",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
Subsystem: subsystem, Subsystem: subsystem,
}), }),
SubmissionTimestamp: promauto.NewGauge(prometheus.GaugeOpts{ submissionTimestamp: promauto.NewGauge(prometheus.GaugeOpts{
Name: "submission_timestamp_ms", Name: "submission_timestamp_ms",
Help: "Timestamp of last batch submitter submission", Help: "Timestamp of last batch submitter submission",
Subsystem: subsystem, Subsystem: subsystem,
}), }),
SubmissionGasUsed: promauto.NewGauge(prometheus.GaugeOpts{ submissionGasUsedWei: promauto.NewGauge(prometheus.GaugeOpts{
Name: "submission_gas_used_wei", Name: "submission_gas_used_wei",
Help: "Gas used to submit each batch", Help: "Gas used to submit each batch",
Subsystem: subsystem, Subsystem: subsystem,
}), }),
BatchesSubmitted: promauto.NewCounter(prometheus.CounterOpts{ batchesSubmitted: promauto.NewCounter(prometheus.CounterOpts{
Name: "batches_submitted", Name: "batches_submitted",
Help: "Count of batches submitted", Help: "Count of batches submitted",
Subsystem: subsystem, Subsystem: subsystem,
}), }),
FailedSubmissions: promauto.NewCounter(prometheus.CounterOpts{ failedSubmissions: promauto.NewCounter(prometheus.CounterOpts{
Name: "failed_submissions", Name: "failed_submissions",
Help: "Count of failed batch submissions", Help: "Count of failed batch submissions",
Subsystem: subsystem, Subsystem: subsystem,
}), }),
BatchTxBuildTime: promauto.NewGauge(prometheus.GaugeOpts{ batchTxBuildTimeMs: promauto.NewGauge(prometheus.GaugeOpts{
Name: "batch_tx_build_time_ms", Name: "batch_tx_build_time_ms",
Help: "Time to construct batch transactions", Help: "Time to construct batch transactions",
Subsystem: subsystem, Subsystem: subsystem,
}), }),
BatchConfirmationTime: promauto.NewGauge(prometheus.GaugeOpts{ batchConfirmationTimeMs: promauto.NewGauge(prometheus.GaugeOpts{
Name: "batch_confirmation_time_ms", Name: "batch_confirmation_time_ms",
Help: "Time to confirm batch transactions", Help: "Time to confirm batch transactions",
Subsystem: subsystem, Subsystem: subsystem,
}), }),
BatchPruneCount: promauto.NewGauge(prometheus.GaugeOpts{
Name: "batch_prune_count",
Help: "Number of times a batch is pruned",
Subsystem: subsystem,
}),
} }
} }
// SubsystemName returns the subsystem name for the metrics group.
func (b *Base) SubsystemName() string {
return b.subsystemName
}
// BalanceETH tracks the amount of ETH in the submitter's account.
func (b *Base) BalanceETH() prometheus.Gauge {
return b.balanceETH
}
// BatchSizeBytes tracks the size of batch submission transactions.
func (b *Base) BatchSizeBytes() prometheus.Summary {
return b.batchSizeBytes
}
// NumElementsPerBatch tracks the number of L2 transactions in each batch
// submission.
func (b *Base) NumElementsPerBatch() prometheus.Summary {
return b.numElementsPerBatch
}
// SubmissionTimestamp tracks the time at which each batch was confirmed.
func (b *Base) SubmissionTimestamp() prometheus.Gauge {
return b.submissionTimestamp
}
// SubmissionGasUsedWei tracks the amount of gas used to submit each batch.
func (b *Base) SubmissionGasUsedWei() prometheus.Gauge {
return b.submissionGasUsedWei
}
// BatchsSubmitted tracks the total number of successful batch submissions.
func (b *Base) BatchesSubmitted() prometheus.Counter {
return b.batchesSubmitted
}
// FailedSubmissions tracks the total number of failed batch submissions.
func (b *Base) FailedSubmissions() prometheus.Counter {
return b.failedSubmissions
}
// BatchTxBuildTimeMs tracks the duration it takes to construct a batch
// transaction.
func (b *Base) BatchTxBuildTimeMs() prometheus.Gauge {
return b.batchTxBuildTimeMs
}
// BatchConfirmationTimeMs tracks the duration it takes to confirm a batch
// transaction.
func (b *Base) BatchConfirmationTimeMs() prometheus.Gauge {
return b.batchConfirmationTimeMs
}
// MakeSubsystemName builds the subsystem name for a group of metrics, which
// prometheus will use to prefix all metrics in the group. If two non-empty
// strings are provided, they are joined with an underscore. If only one
// non-empty string is provided, that name will be used alone. Otherwise an
// empty string is returned after converting the characters to lower case.
//
// NOTE: This method panics if spaces are included in either string.
func MakeSubsystemName(serviceName string, subServiceName string) string {
var subsystem string
switch {
case serviceName != "" && subServiceName != "":
subsystem = fmt.Sprintf("%s_%s", serviceName, subServiceName)
case serviceName != "":
subsystem = serviceName
default:
subsystem = subServiceName
}
if strings.ContainsAny(subsystem, " ") {
panic(fmt.Sprintf("metrics name \"%s\"cannot have spaces", subsystem))
}
return strings.ToLower(subsystem)
}
...@@ -31,7 +31,7 @@ type Driver interface { ...@@ -31,7 +31,7 @@ type Driver interface {
WalletAddr() common.Address WalletAddr() common.Address
// Metrics returns the subservice telemetry object. // Metrics returns the subservice telemetry object.
Metrics() *metrics.Metrics Metrics() metrics.Metrics
// ClearPendingTx a publishes a transaction at the next available nonce in // ClearPendingTx a publishes a transaction at the next available nonce in
// order to clear any transactions in the mempool left over from a prior // order to clear any transactions in the mempool left over from a prior
...@@ -83,7 +83,7 @@ type Service struct { ...@@ -83,7 +83,7 @@ type Service struct {
cancel func() cancel func()
txMgr txmgr.TxManager txMgr txmgr.TxManager
metrics *metrics.Metrics metrics metrics.Metrics
wg sync.WaitGroup wg sync.WaitGroup
} }
...@@ -147,7 +147,7 @@ func (s *Service) eventLoop() { ...@@ -147,7 +147,7 @@ func (s *Service) eventLoop() {
log.Error(name+" unable to get current balance", "err", err) log.Error(name+" unable to get current balance", "err", err)
continue continue
} }
s.metrics.ETHBalance.Set(weiToEth64(balance)) s.metrics.BalanceETH().Set(weiToEth64(balance))
// Determine the range of L2 blocks that the batch submitter has not // Determine the range of L2 blocks that the batch submitter has not
// processed, and needs to take action on. // processed, and needs to take action on.
...@@ -186,7 +186,7 @@ func (s *Service) eventLoop() { ...@@ -186,7 +186,7 @@ func (s *Service) eventLoop() {
continue continue
} }
batchTxBuildTime := time.Since(batchTxBuildStart) / time.Millisecond batchTxBuildTime := time.Since(batchTxBuildStart) / time.Millisecond
s.metrics.BatchTxBuildTime.Set(float64(batchTxBuildTime)) s.metrics.BatchTxBuildTimeMs().Set(float64(batchTxBuildTime))
// Record the size of the batch transaction. // Record the size of the batch transaction.
var txBuf bytes.Buffer var txBuf bytes.Buffer
...@@ -194,7 +194,7 @@ func (s *Service) eventLoop() { ...@@ -194,7 +194,7 @@ func (s *Service) eventLoop() {
log.Error(name+" unable to encode batch tx", "err", err) log.Error(name+" unable to encode batch tx", "err", err)
continue continue
} }
s.metrics.BatchSizeInBytes.Observe(float64(len(txBuf.Bytes()))) s.metrics.BatchSizeBytes().Observe(float64(len(txBuf.Bytes())))
// Construct the transaction submission clousure that will attempt // Construct the transaction submission clousure that will attempt
// to send the next transaction at the given nonce and gas price. // to send the next transaction at the given nonce and gas price.
...@@ -214,7 +214,7 @@ func (s *Service) eventLoop() { ...@@ -214,7 +214,7 @@ func (s *Service) eventLoop() {
if err != nil { if err != nil {
log.Error(name+" unable to publish batch tx", log.Error(name+" unable to publish batch tx",
"err", err) "err", err)
s.metrics.FailedSubmissions.Inc() s.metrics.FailedSubmissions().Inc()
continue continue
} }
...@@ -223,10 +223,10 @@ func (s *Service) eventLoop() { ...@@ -223,10 +223,10 @@ func (s *Service) eventLoop() {
"tx_hash", receipt.TxHash) "tx_hash", receipt.TxHash)
batchConfirmationTime := time.Since(batchConfirmationStart) / batchConfirmationTime := time.Since(batchConfirmationStart) /
time.Millisecond time.Millisecond
s.metrics.BatchConfirmationTime.Set(float64(batchConfirmationTime)) s.metrics.BatchConfirmationTimeMs().Set(float64(batchConfirmationTime))
s.metrics.BatchesSubmitted.Inc() s.metrics.BatchesSubmitted().Inc()
s.metrics.SubmissionGasUsed.Set(float64(receipt.GasUsed)) s.metrics.SubmissionGasUsedWei().Set(float64(receipt.GasUsed))
s.metrics.SubmissionTimestamp.Set(float64(time.Now().UnixNano() / 1e6)) s.metrics.SubmissionTimestamp().Set(float64(time.Now().UnixNano() / 1e6))
case err := <-s.ctx.Done(): case err := <-s.ctx.Done():
log.Error(name+" service shutting down", "err", err) log.Error(name+" service shutting down", "err", err)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment