Commit 56a6979e authored by Seungju Lee's avatar Seungju Lee

refactor: separate out rpc related metrics from op-node/metrics to op-service/metrics

parent 07647f59
...@@ -3,8 +3,6 @@ package metrics ...@@ -3,8 +3,6 @@ package metrics
import ( import (
"context" "context"
"errors"
"fmt"
"net" "net"
"strconv" "strconv"
"time" "time"
...@@ -21,9 +19,7 @@ import ( ...@@ -21,9 +19,7 @@ import (
"github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/eth"
) )
...@@ -31,9 +27,6 @@ import ( ...@@ -31,9 +27,6 @@ import (
const ( const (
Namespace = "op_node" Namespace = "op_node"
RPCServerSubsystem = "rpc_server"
RPCClientSubsystem = "rpc_client"
BatchMethod = "<batch>" BatchMethod = "<batch>"
) )
...@@ -87,11 +80,7 @@ type Metrics struct { ...@@ -87,11 +80,7 @@ type Metrics struct {
Info *prometheus.GaugeVec Info *prometheus.GaugeVec
Up prometheus.Gauge Up prometheus.Gauge
RPCServerRequestsTotal *prometheus.CounterVec metrics.RPCMetrics
RPCServerRequestDurationSeconds *prometheus.HistogramVec
RPCClientRequestsTotal *prometheus.CounterVec
RPCClientRequestDurationSeconds *prometheus.HistogramVec
RPCClientResponsesTotal *prometheus.CounterVec
L1SourceCache *CacheMetrics L1SourceCache *CacheMetrics
L2SourceCache *CacheMetrics L2SourceCache *CacheMetrics
...@@ -186,49 +175,7 @@ func NewMetrics(procName string) *Metrics { ...@@ -186,49 +175,7 @@ func NewMetrics(procName string) *Metrics {
Help: "1 if the op node has finished starting up", Help: "1 if the op node has finished starting up",
}), }),
RPCServerRequestsTotal: factory.NewCounterVec(prometheus.CounterOpts{ RPCMetrics: *metrics.NewRPCMetrics(procName, Namespace),
Namespace: ns,
Subsystem: RPCServerSubsystem,
Name: "requests_total",
Help: "Total requests to the RPC server",
}, []string{
"method",
}),
RPCServerRequestDurationSeconds: factory.NewHistogramVec(prometheus.HistogramOpts{
Namespace: ns,
Subsystem: RPCServerSubsystem,
Name: "request_duration_seconds",
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10},
Help: "Histogram of RPC server request durations",
}, []string{
"method",
}),
RPCClientRequestsTotal: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: ns,
Subsystem: RPCClientSubsystem,
Name: "requests_total",
Help: "Total RPC requests initiated by the opnode's RPC client",
}, []string{
"method",
}),
RPCClientRequestDurationSeconds: factory.NewHistogramVec(prometheus.HistogramOpts{
Namespace: ns,
Subsystem: RPCClientSubsystem,
Name: "request_duration_seconds",
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10},
Help: "Histogram of RPC client request durations",
}, []string{
"method",
}),
RPCClientResponsesTotal: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: ns,
Subsystem: RPCClientSubsystem,
Name: "responses_total",
Help: "Total RPC request responses received by the opnode's RPC client",
}, []string{
"method",
"error",
}),
L1SourceCache: NewCacheMetrics(factory, ns, "l1_source_cache", "L1 Source cache"), L1SourceCache: NewCacheMetrics(factory, ns, "l1_source_cache", "L1 Source cache"),
L2SourceCache: NewCacheMetrics(factory, ns, "l2_source_cache", "L2 Source cache"), L2SourceCache: NewCacheMetrics(factory, ns, "l2_source_cache", "L2 Source cache"),
...@@ -467,53 +414,6 @@ func (m *Metrics) RecordUp() { ...@@ -467,53 +414,6 @@ func (m *Metrics) RecordUp() {
m.Up.Set(1) m.Up.Set(1)
} }
// RecordRPCServerRequest is a helper method to record an incoming RPC
// call to the opnode's RPC server. It bumps the requests metric,
// and tracks how long it takes to serve a response.
func (m *Metrics) RecordRPCServerRequest(method string) func() {
m.RPCServerRequestsTotal.WithLabelValues(method).Inc()
timer := prometheus.NewTimer(m.RPCServerRequestDurationSeconds.WithLabelValues(method))
return func() {
timer.ObserveDuration()
}
}
// RecordRPCClientRequest is a helper method to record an RPC client
// request. It bumps the requests metric, tracks the response
// duration, and records the response's error code.
func (m *Metrics) RecordRPCClientRequest(method string) func(err error) {
m.RPCClientRequestsTotal.WithLabelValues(method).Inc()
timer := prometheus.NewTimer(m.RPCClientRequestDurationSeconds.WithLabelValues(method))
return func(err error) {
m.RecordRPCClientResponse(method, err)
timer.ObserveDuration()
}
}
// RecordRPCClientResponse records an RPC response. It will
// convert the passed-in error into something metrics friendly.
// Nil errors get converted into <nil>, RPC errors are converted
// into rpc_<error code>, HTTP errors are converted into
// http_<status code>, and everything else is converted into
// <unknown>.
func (m *Metrics) RecordRPCClientResponse(method string, err error) {
var errStr string
var rpcErr rpc.Error
var httpErr rpc.HTTPError
if err == nil {
errStr = "<nil>"
} else if errors.As(err, &rpcErr) {
errStr = fmt.Sprintf("rpc_%d", rpcErr.ErrorCode())
} else if errors.As(err, &httpErr) {
errStr = fmt.Sprintf("http_%d", httpErr.StatusCode)
} else if errors.Is(err, ethereum.NotFound) {
errStr = "<not found>"
} else {
errStr = "<unknown>"
}
m.RPCClientResponsesTotal.WithLabelValues(method, errStr).Inc()
}
func (m *Metrics) SetDerivationIdle(status bool) { func (m *Metrics) SetDerivationIdle(status bool) {
var val float64 var val float64
if status { if status {
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/version" "github.com/ethereum-optimism/optimism/op-node/version"
"github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/metrics"
"github.com/ethereum-optimism/optimism/op-service/rpc" "github.com/ethereum-optimism/optimism/op-service/rpc"
) )
...@@ -36,7 +37,7 @@ type adminAPI struct { ...@@ -36,7 +37,7 @@ type adminAPI struct {
dr driverClient dr driverClient
} }
func NewAdminAPI(dr driverClient, m rpc.RpcMetrics, log log.Logger) *adminAPI { func NewAdminAPI(dr driverClient, m metrics.RPCMetricer, log log.Logger) *adminAPI {
return &adminAPI{ return &adminAPI{
dr: dr, dr: dr,
CommonAdminAPI: rpc.NewCommonAdminAPI(m, log), CommonAdminAPI: rpc.NewCommonAdminAPI(m, log),
...@@ -72,10 +73,10 @@ type nodeAPI struct { ...@@ -72,10 +73,10 @@ type nodeAPI struct {
client l2EthClient client l2EthClient
dr driverClient dr driverClient
log log.Logger log log.Logger
m rpc.RpcMetrics m metrics.RPCMetricer
} }
func NewNodeAPI(config *rollup.Config, l2Client l2EthClient, dr driverClient, log log.Logger, m rpc.RpcMetrics) *nodeAPI { func NewNodeAPI(config *rollup.Config, l2Client l2EthClient, dr driverClient, log log.Logger, m metrics.RPCMetricer) *nodeAPI {
return &nodeAPI{ return &nodeAPI{
config: config, config: config,
client: l2Client, client: l2Client,
......
...@@ -58,3 +58,9 @@ type TestRPCMetrics struct{} ...@@ -58,3 +58,9 @@ type TestRPCMetrics struct{}
func (n *TestRPCMetrics) RecordRPCServerRequest(method string) func() { func (n *TestRPCMetrics) RecordRPCServerRequest(method string) func() {
return func() {} return func() {}
} }
func (n *TestRPCMetrics) RecordRPCClientRequest(method string) func(err error) {
return func(err error) {}
}
func (n *TestRPCMetrics) RecordRPCClientResponse(method string, err error) {}
package metrics
import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/rpc"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
)
const (
RPCServerSubsystem = "rpc_server"
RPCClientSubsystem = "rpc_client"
)
type RPCMetricer interface {
RecordRPCServerRequest(method string) func()
RecordRPCClientRequest(method string) func(err error)
RecordRPCClientResponse(method string, err error)
}
// RPCMetrics tracks all the RPC metrics for the op-service RPC.
type RPCMetrics struct {
RPCServerRequestsTotal *prometheus.CounterVec
RPCServerRequestDurationSeconds *prometheus.HistogramVec
RPCClientRequestsTotal *prometheus.CounterVec
RPCClientRequestDurationSeconds *prometheus.HistogramVec
RPCClientResponsesTotal *prometheus.CounterVec
}
// NewRPCMetrics creates a new RPCMetrics instance with the given process name, and
// namespace for the service.
func NewRPCMetrics(procName, namespace string) *RPCMetrics {
if procName == "" {
procName = "default"
}
ns := namespace + "_" + procName
registry := prometheus.NewRegistry()
registry.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))
registry.MustRegister(collectors.NewGoCollector())
factory := With(registry)
return &RPCMetrics{
RPCServerRequestsTotal: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: ns,
Subsystem: RPCServerSubsystem,
Name: "requests_total",
Help: "Total requests to the RPC server",
}, []string{
"method",
}),
RPCServerRequestDurationSeconds: factory.NewHistogramVec(prometheus.HistogramOpts{
Namespace: ns,
Subsystem: RPCServerSubsystem,
Name: "request_duration_seconds",
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10},
Help: "Histogram of RPC server request durations",
}, []string{
"method",
}),
RPCClientRequestsTotal: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: ns,
Subsystem: RPCClientSubsystem,
Name: "requests_total",
Help: "Total RPC requests initiated by the opnode's RPC client",
}, []string{
"method",
}),
RPCClientRequestDurationSeconds: factory.NewHistogramVec(prometheus.HistogramOpts{
Namespace: ns,
Subsystem: RPCClientSubsystem,
Name: "request_duration_seconds",
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10},
Help: "Histogram of RPC client request durations",
}, []string{
"method",
}),
RPCClientResponsesTotal: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: ns,
Subsystem: RPCClientSubsystem,
Name: "responses_total",
Help: "Total RPC request responses received by the opnode's RPC client",
}, []string{
"method",
"error",
}),
}
}
// RecordRPCServerRequest is a helper method to record an incoming RPC
// call to the opnode's RPC server. It bumps the requests metric,
// and tracks how long it takes to serve a response.
func (m *RPCMetrics) RecordRPCServerRequest(method string) func() {
m.RPCServerRequestsTotal.WithLabelValues(method).Inc()
timer := prometheus.NewTimer(m.RPCServerRequestDurationSeconds.WithLabelValues(method))
return func() {
timer.ObserveDuration()
}
}
// RecordRPCClientRequest is a helper method to record an RPC client
// request. It bumps the requests metric, tracks the response
// duration, and records the response's error code.
func (m *RPCMetrics) RecordRPCClientRequest(method string) func(err error) {
m.RPCClientRequestsTotal.WithLabelValues(method).Inc()
timer := prometheus.NewTimer(m.RPCClientRequestDurationSeconds.WithLabelValues(method))
return func(err error) {
m.RecordRPCClientResponse(method, err)
timer.ObserveDuration()
}
}
// RecordRPCClientResponse records an RPC response. It will
// convert the passed-in error into something metrics friendly.
// Nil errors get converted into <nil>, RPC errors are converted
// into rpc_<error code>, HTTP errors are converted into
// http_<status code>, and everything else is converted into
// <unknown>.
func (m *RPCMetrics) RecordRPCClientResponse(method string, err error) {
var errStr string
var rpcErr rpc.Error
var httpErr rpc.HTTPError
if err == nil {
errStr = "<nil>"
} else if errors.As(err, &rpcErr) {
errStr = fmt.Sprintf("rpc_%d", rpcErr.ErrorCode())
} else if errors.As(err, &httpErr) {
errStr = fmt.Sprintf("http_%d", httpErr.StatusCode)
} else if errors.Is(err, ethereum.NotFound) {
errStr = "<not found>"
} else {
errStr = "<unknown>"
}
m.RPCClientResponsesTotal.WithLabelValues(method, errStr).Inc()
}
...@@ -5,20 +5,16 @@ import ( ...@@ -5,20 +5,16 @@ import (
"fmt" "fmt"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum-optimism/optimism/op-service/metrics"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
type RpcMetrics interface {
// RecordRPCServerRequest returns a function that records the duration of serving the given RPC method
RecordRPCServerRequest(method string) func()
}
type CommonAdminAPI struct { type CommonAdminAPI struct {
M RpcMetrics M metrics.RPCMetricer
log log.Logger log log.Logger
} }
func NewCommonAdminAPI(m RpcMetrics, log log.Logger) *CommonAdminAPI { func NewCommonAdminAPI(m metrics.RPCMetricer, log log.Logger) *CommonAdminAPI {
return &CommonAdminAPI{ return &CommonAdminAPI{
M: m, M: m,
log: log, log: log,
......
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