@@ -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.
1314type 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.
3845func 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,
5770func (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.
86105func (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}
0 commit comments