Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: add support for simple payments related metrics #9537

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions monitoring/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//go:build monitoring
// +build monitoring

package monitoring

import (
"sync"

"github.com/lightningnetwork/lnd/lncfg"
)

// MetricGroupCreator is a factory function that initializes a metric group.
type MetricGroupCreator func(cfg *lncfg.Prometheus) (MetricGroup, error)

// Global registry for all metric groups.
var (
// metricGroups is a global variable of all registered metrics
// protected by the mutex below. All new MetricGroups should add
// themselves to this map within the init() method of their file.
metricGroups = make(map[string]MetricGroupCreator)

// activeGroups is a global map of all active metric groups. This can
// be used by some of the "static' package level methods to look up the
// target metric group to export observations.
activeMetrics = make(map[string]MetricGroup)

metricsMtx sync.Mutex
)

// MetricGroup is the primary interface for metric groups.
type MetricGroup interface {
// Name returns the name of the metric group.
Name() string

// RegisterMetrics registers all metrics within the group.
RegisterMetrics() error

// ShouldRegister indicates whether this groups metrics should actually
// be registered.
ShouldRegister(cfg *lncfg.Prometheus) bool
}

// RegisterMetricGroup adds a new metric group to the registry.
func RegisterMetricGroup(name string, creator MetricGroupCreator) {
metricsMtx.Lock()
defer metricsMtx.Unlock()
metricGroups[name] = creator
}

// InitializeMetrics initializes and registers all active metric groups.
func InitializeMetrics(cfg *lncfg.Prometheus) error {
metricsMtx.Lock()
defer metricsMtx.Unlock()

for name, creator := range metricGroups {
// We'll pass the configuration struct to permit conditional
// metric registration in the future.
group, err := creator(cfg)
if err != nil {
return err
}

// Check whether this metric group should be registered.
if !group.ShouldRegister(cfg) {
continue
}

if err := group.RegisterMetrics(); err != nil {
return err
}

activeMetrics[name] = group
}

return nil
}
10 changes: 10 additions & 0 deletions monitoring/monitoring_off.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ func ExportPrometheusMetrics(_ *grpc.Server, _ lncfg.Prometheus) error {
return fmt.Errorf("lnd must be built with the monitoring tag to " +
"enable exporting Prometheus metrics")
}

// IncrementPaymentCount increments a counter tracking the number of payments
// made by lnd when monitoring is enabled. This method no-ops as monitoring is
// disabled.
func IncrementPaymentCount() {}

// IncrementHTLCAttemptCount increments a counter tracking the number of HTLC
// attempts made by lnd when monitoring is enabled. This method no-ops as
// monitoring is disabled.
func IncrementHTLCAttemptCount() {}
18 changes: 15 additions & 3 deletions monitoring/monitoring_on.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ func GetPromInterceptors() ([]grpc.UnaryServerInterceptor, []grpc.StreamServerIn
return unaryInterceptors, streamInterceptors
}

// ExportPrometheusMetrics sets server options, registers gRPC metrics and
// launches the Prometheus exporter on the specified address.
// ExportPrometheusMetrics sets server options, registers gRPC metrics,
// and launches the Prometheus exporter on the specified address.
func ExportPrometheusMetrics(grpcServer *grpc.Server, cfg lncfg.Prometheus) error {
var metricErr error
started.Do(func() {
log.Infof("Prometheus exporter started on %v/metrics", cfg.Listen)

// Register gRPC Prometheus interceptors.
grpc_prometheus.Register(grpcServer)

// Enable the histograms which can allow plotting latency
Expand All @@ -43,11 +45,21 @@ func ExportPrometheusMetrics(grpcServer *grpc.Server, cfg lncfg.Prometheus) erro
grpc_prometheus.EnableHandlingTimeHistogram()
}

// Initialize additional metric groups (e.g., payment tracking).
err := InitializeMetrics(&cfg)
if err != nil {
log.Warnf("Failed to initialize additional metrics: %v",
err)

metricErr = err
}

// Start the Prometheus HTTP handler.
http.Handle("/metrics", promhttp.Handler())
go func() {
http.ListenAndServe(cfg.Listen, nil)
}()
})

return nil
return metricErr
}
79 changes: 79 additions & 0 deletions monitoring/payments_metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//go:build monitoring
// +build monitoring

package monitoring

import (
"github.com/lightningnetwork/lnd/lncfg"
"github.com/prometheus/client_golang/prometheus"
)

const paymentsMetricGroupName string = "payments"

// paymentMetrics tracks payment-related Prometheus metrics.
type paymentMetrics struct {
totalPayments prometheus.Counter
totalHTLCAttempts prometheus.Counter
}

// NewPaymentMetrics creates a new instance of payment metrics.
func NewPaymentMetrics(cfg *lncfg.Prometheus) (MetricGroup, error) {
return &paymentMetrics{
totalPayments: prometheus.NewCounter(prometheus.CounterOpts{
Name: "lnd_total_payments",
Help: "Total number of payments initiated",
}),
totalHTLCAttempts: prometheus.NewCounter(prometheus.CounterOpts{
Name: "lnd_total_htlc_attempts",
Help: "Total number of HTLC attempts",
}),
}, nil
}

// Name returns the metric group name.
func (p *paymentMetrics) Name() string {
return paymentsMetricGroupName
}

// RegisterMetrics registers payment-related Prometheus metrics.
func (p *paymentMetrics) RegisterMetrics() error {
err := prometheus.Register(p.totalPayments)
if err != nil {
return err
}
return prometheus.Register(p.totalHTLCAttempts)
}

// ShouldRegister indicates whether the payments related metrics should be
// registered with prometheus.
func (p *paymentMetrics) ShouldRegister(cfg *lncfg.Prometheus) bool {
// TODO: Can condition this on application config.
return true
}

// IncrementPaymentCount increments the counter tracking the number of payments
// made by lnd when monitoring is enabled and the metric is configured
func IncrementPaymentCount() {
group, ok := activeMetrics[paymentsMetricGroupName].(*paymentMetrics)
if !ok {
return
}

group.totalPayments.Inc()
}

// IncrementHTLCAttemptCount increments the counter tracking the number of HTLC
// attempts made by lnd when monitoring is enabled and the metric is configured.
func IncrementHTLCAttemptCount() {
group, ok := activeMetrics[paymentsMetricGroupName].(*paymentMetrics)
if !ok {
return
}

group.totalHTLCAttempts.Inc()
}

// Register the payments metric group.
func init() {
RegisterMetricGroup(paymentsMetricGroupName, NewPaymentMetrics)
}
4 changes: 4 additions & 0 deletions routing/control_tower.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/monitoring"
"github.com/lightningnetwork/lnd/multimutex"
"github.com/lightningnetwork/lnd/queue"
)
Expand Down Expand Up @@ -191,6 +192,9 @@ func (p *controlTower) InitPayment(paymentHash lntypes.Hash,
return err
}

// Observe the creation of a new payment.
monitoring.IncrementPaymentCount()

// Take lock before querying the db to prevent missing or duplicating
// an update.
p.paymentsMtx.Lock(paymentHash)
Expand Down
4 changes: 4 additions & 0 deletions routing/payment_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/monitoring"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/routing/shards"
"github.com/lightningnetwork/lnd/tlv"
Expand Down Expand Up @@ -596,6 +597,9 @@ func (p *paymentLifecycle) registerAttempt(rt *route.Route,
p.identifier, &attempt.HTLCAttemptInfo,
)

// Observe a new HTLC attempt for the payment.
monitoring.IncrementHTLCAttemptCount()

return attempt, err
}

Expand Down
Loading