monitoring: add support for payments related metrics

This commit is contained in:
Calvin Zachman 2025-02-20 10:35:55 -06:00
parent 09a4d7e224
commit 951849709b
No known key found for this signature in database
GPG key ID: 52AAA845E345D42E
4 changed files with 180 additions and 3 deletions

76
monitoring/metrics.go Normal file
View file

@ -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
}

View file

@ -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() {}

View file

@ -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
@ -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
}

View file

@ -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)
}