Skip to content

Commit 5544239

Browse files
committed
collectors: add time_to_unlock_secs
1 parent 373684e commit 5544239

File tree

3 files changed

+65
-31
lines changed

3 files changed

+65
-31
lines changed

collectors/prometheus.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"net/http"
77
"os"
88
"path/filepath"
9+
"time"
910

1011
"github.com/btcsuite/btcd/btcutil"
1112
"github.com/lightninglabs/lndclient"
@@ -70,6 +71,9 @@ type MonitoringConfig struct {
7071

7172
// DisableHtlc disables collection of HTLCs metrics
7273
DisableHtlc bool
74+
75+
// ProgramStartTime stores a best-effort estimate of when lnd/lndmon was started.
76+
ProgramStartTime time.Time
7377
}
7478

7579
func DefaultConfig() *PrometheusConfig {
@@ -104,7 +108,7 @@ func NewPrometheusExporter(cfg *PrometheusConfig, lnd *lndclient.LndServices,
104108
NewWalletCollector(lnd, errChan),
105109
NewPeerCollector(lnd.Client, errChan),
106110
NewInfoCollector(lnd.Client, errChan),
107-
NewStateCollector(lnd, errChan),
111+
NewStateCollector(lnd, errChan, monitoringCfg.ProgramStartTime),
108112
}
109113

110114
if !monitoringCfg.DisableHtlc {

collectors/state_collector.go

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,29 @@ import (
1010
"github.com/prometheus/client_golang/prometheus"
1111
)
1212

13+
// StateCollector is a collector that keeps track of LND's state.
1314
type StateCollector struct {
1415
lnd *lndclient.LndServices
1516

16-
// Use one gauge to track the starting time of LND.
17+
// timeToStartDesc is a gauge to track time from unlocked to started of LND.
1718
timeToStartDesc *prometheus.Desc
1819

19-
// startTime records a best-effort timestamp of when LND was started.
20-
startTime time.Time
20+
// timeToUnlockDesc is a gauge to track the time to unlock of LND.
21+
timeToUnlockDesc *prometheus.Desc
2122

22-
// endTime records when LND makes a transition from RPC_ACTIVE to
23+
// programStartTime records a best-effort timestamp of when lndmon was started.
24+
programStartTime time.Time
25+
26+
// unlockTime records a best-effort timestamp of when LND was unlocked.
27+
unlockTime time.Time
28+
29+
// endTime records when LND makes a transition from UNLOCKED to
2330
// SERVER_ACTIVE.
2431
// If lndmon starts after LND has already reached SERVER_ACTIVE, no
2532
// startup time metric will be emitted.
2633
endTime time.Time
2734

28-
// mutex is a lock for preventing concurrent writes to startTime or
35+
// mutex is a lock for preventing concurrent writes to unlockTime or
2936
// endTime.
3037
mutex sync.RWMutex
3138

@@ -36,17 +43,23 @@ type StateCollector struct {
3643

3744
// NewStateCollector returns a new instance of the StateCollector.
3845
func NewStateCollector(lnd *lndclient.LndServices,
39-
errChan chan<- error) *StateCollector {
46+
errChan chan<- error, programStartTime time.Time) *StateCollector {
4047

4148
sc := &StateCollector{
4249
lnd: lnd,
4350
timeToStartDesc: prometheus.NewDesc(
44-
"lnd_time_to_start_secs",
45-
"time to start in seconds",
51+
"lnd_time_to_start_millisecs",
52+
"time to start in milliseconds",
53+
nil, nil,
54+
),
55+
timeToUnlockDesc: prometheus.NewDesc(
56+
"lnd_time_to_unlock_millisecs",
57+
"time to unlocked in milliseconds",
4658
nil, nil,
4759
),
48-
startTime: time.Now(),
49-
errChan: errChan,
60+
programStartTime: programStartTime,
61+
unlockTime: time.Now(),
62+
errChan: errChan,
5063
}
5164

5265
go sc.monitorStateChanges()
@@ -57,24 +70,30 @@ func NewStateCollector(lnd *lndclient.LndServices,
5770
func (s *StateCollector) monitorStateChanges() {
5871
var serverActiveReached bool
5972

60-
for {
61-
state, err := s.lnd.State.GetState(context.Background())
62-
if err != nil {
63-
s.errChan <- fmt.Errorf("StateCollector GetState failed with: %v", err)
64-
continue
65-
}
66-
67-
s.mutex.Lock()
68-
if state == lndclient.WalletStateRPCActive && !s.startTime.IsZero() {
69-
s.endTime = time.Now()
70-
serverActiveReached = true
71-
}
72-
s.mutex.Unlock()
73+
stateUpdates, errChan, err := s.lnd.State.SubscribeState(context.Background())
74+
if err != nil {
75+
s.errChan <- fmt.Errorf("StateCollector SubscribeState failed with: %v", err)
76+
return
77+
}
7378

74-
if serverActiveReached {
75-
break
79+
for {
80+
select {
81+
case state := <-stateUpdates:
82+
s.mutex.Lock()
83+
if state == lndclient.WalletStateServerActive && !s.unlockTime.IsZero() {
84+
s.endTime = time.Now()
85+
serverActiveReached = true
86+
}
87+
s.mutex.Unlock()
88+
89+
if serverActiveReached {
90+
return
91+
}
92+
93+
case err := <-errChan:
94+
s.errChan <- fmt.Errorf("StateCollector state update failed with: %v", err)
95+
return
7696
}
77-
time.Sleep(1 * time.Second)
7897
}
7998
}
8099

@@ -85,6 +104,7 @@ func (s *StateCollector) monitorStateChanges() {
85104
// NOTE: Part of the prometheus.Collector interface.
86105
func (s *StateCollector) Describe(ch chan<- *prometheus.Desc) {
87106
ch <- s.timeToStartDesc
107+
ch <- s.timeToUnlockDesc
88108
}
89109

90110
// Collect is called by the Prometheus registry when collecting metrics.
@@ -95,11 +115,17 @@ func (s *StateCollector) Collect(ch chan<- prometheus.Metric) {
95115
s.mutex.RLock()
96116
defer s.mutex.RUnlock()
97117

98-
// We have set both a startTime and endTime, calculate the difference and emit a metric.
99-
if !s.startTime.IsZero() && !s.endTime.IsZero() {
100-
timeToStartInSecs := s.endTime.Sub(s.startTime).Seconds()
118+
// We have set unlockTime and endTime.
119+
// Calculate the differences and emit a metric.
120+
if !s.unlockTime.IsZero() && !s.endTime.IsZero() {
121+
timeToUnlockInMSecs := s.unlockTime.Sub(s.programStartTime).Milliseconds()
122+
timeToStartInMSecs := s.endTime.Sub(s.unlockTime).Milliseconds()
123+
ch <- prometheus.MustNewConstMetric(
124+
s.timeToStartDesc, prometheus.GaugeValue, float64(timeToStartInMSecs),
125+
)
126+
101127
ch <- prometheus.MustNewConstMetric(
102-
s.timeToStartDesc, prometheus.GaugeValue, timeToStartInSecs,
128+
s.timeToUnlockDesc, prometheus.GaugeValue, float64(timeToUnlockInMSecs),
103129
)
104130
}
105131
}

lndmon.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7+
"time"
78

89
flags "github.com/jessevdk/go-flags"
910
"github.com/lightninglabs/lndclient"
@@ -37,6 +38,8 @@ func start() error {
3738
return fmt.Errorf("could not intercept signal: %v", err)
3839
}
3940

41+
programStartTime := time.Now()
42+
4043
// Initialize our lnd client, requiring at least lnd v0.11.
4144
lnd, err := lndclient.NewLndServices(
4245
&lndclient.LndServicesConfig{
@@ -70,6 +73,7 @@ func start() error {
7073
}
7174
monitoringCfg.PrimaryNode = &primaryNode
7275
}
76+
monitoringCfg.ProgramStartTime = programStartTime
7377

7478
// Start our Prometheus exporter. This exporter spawns a goroutine
7579
// that pulls metrics from our lnd client on a set interval.

0 commit comments

Comments
 (0)