@@ -3,48 +3,216 @@ package sync
3
3
import (
4
4
"context"
5
5
"sync/atomic"
6
+ "time"
6
7
7
8
"go.opentelemetry.io/otel"
9
+ "go.opentelemetry.io/otel/attribute"
8
10
"go.opentelemetry.io/otel/metric"
9
11
)
10
12
11
13
var meter = otel .Meter ("header/sync" )
12
14
13
15
type metrics struct {
14
- totalSynced atomic.Int64
15
- totalSyncedGauge metric.Float64ObservableGauge
16
+ syncerReg metric.Registration
17
+
18
+ subjectiveHeadInst metric.Int64ObservableGauge
19
+ syncLoopRunningInst metric.Int64ObservableGauge
20
+
21
+ syncLoopStarted metric.Int64Counter
22
+ trustedPeersOutOfSync metric.Int64Counter
23
+ unrecentHeader metric.Int64Counter
24
+ subjectiveInit metric.Int64Counter
25
+
26
+ subjectiveHead atomic.Int64
27
+
28
+ syncLoopDurationHist metric.Float64Histogram
29
+ syncLoopActive atomic.Int64
30
+ syncStartedTs time.Time
31
+
32
+ requestRangeTimeHist metric.Float64Histogram
33
+ requestRangeStartTs time.Time
34
+
35
+ blockTime metric.Float64Histogram
36
+ prevHeader time.Time
16
37
}
17
38
18
39
func newMetrics () (* metrics , error ) {
19
- totalSynced , err := meter .Float64ObservableGauge (
20
- "total_synced_headers " ,
21
- metric .WithDescription ("total synced headers " ),
40
+ syncLoopStarted , err := meter .Int64Counter (
41
+ "hdr_sync_loop_started_counter " ,
42
+ metric .WithDescription ("sync loop started shows that syncing is in progress " ),
22
43
)
23
44
if err != nil {
24
45
return nil , err
25
46
}
26
47
27
- m := & metrics {
28
- totalSyncedGauge : totalSynced ,
48
+ trustedPeersOutOfSync , err := meter .Int64Counter (
49
+ "hdr_sync_trust_peers_out_of_sync_counter" ,
50
+ metric .WithDescription ("trusted peers out of sync and gave outdated header" ),
51
+ )
52
+ if err != nil {
53
+ return nil , err
29
54
}
30
55
31
- callback := func (ctx context.Context , observer metric.Observer ) error {
32
- observer .ObserveFloat64 (totalSynced , float64 (m .totalSynced .Load ()))
33
- return nil
56
+ unrecentHeader , err := meter .Int64Counter (
57
+ "hdr_sync_unrecent_header_counter" ,
58
+ metric .WithDescription ("tracks every time Syncer returns an unrecent header" ),
59
+ )
60
+ if err != nil {
61
+ return nil , err
34
62
}
35
- _ , err = meter .RegisterCallback (callback , totalSynced )
63
+
64
+ subjectiveInit , err := meter .Int64Counter (
65
+ "hdr_sync_subjective_init_counter" ,
66
+ metric .WithDescription (
67
+ "tracks how many times is the node initialized " ,
68
+ ),
69
+ )
70
+ if err != nil {
71
+ return nil , err
72
+ }
73
+
74
+ subjectiveHead , err := meter .Int64ObservableGauge (
75
+ "hdr_sync_subjective_head_gauge" ,
76
+ metric .WithDescription ("subjective head height" ),
77
+ )
78
+ if err != nil {
79
+ return nil , err
80
+ }
81
+
82
+ syncLoopDurationHist , err := meter .Float64Histogram (
83
+ "hdr_sync_loop_time_hist" ,
84
+ metric .WithDescription ("tracks the duration of syncing" ))
85
+ if err != nil {
86
+ return nil , err
87
+ }
88
+
89
+ requestRangeTimeHist , err := meter .Float64Histogram ("hdr_sync_range_request_time_hist" ,
90
+ metric .WithDescription ("tracks the duration of GetRangeByHeight requests" ))
91
+ if err != nil {
92
+ return nil , err
93
+ }
94
+
95
+ syncLoopRunningInst , err := meter .Int64ObservableGauge (
96
+ "hdr_sync_loop_status_gauge" ,
97
+ metric .WithDescription ("reports whether syncing is active or not" ))
98
+ if err != nil {
99
+ return nil , err
100
+ }
101
+
102
+ blockTime , err := meter .Float64Histogram (
103
+ "hdr_sync_actual_blockTime_ts_hist" ,
104
+ metric .WithDescription ("duration between creation of 2 blocks" ),
105
+ )
106
+ if err != nil {
107
+ return nil , err
108
+ }
109
+
110
+ m := & metrics {
111
+ syncLoopStarted : syncLoopStarted ,
112
+ trustedPeersOutOfSync : trustedPeersOutOfSync ,
113
+ unrecentHeader : unrecentHeader ,
114
+ subjectiveInit : subjectiveInit ,
115
+ syncLoopDurationHist : syncLoopDurationHist ,
116
+ syncLoopRunningInst : syncLoopRunningInst ,
117
+ requestRangeTimeHist : requestRangeTimeHist ,
118
+ blockTime : blockTime ,
119
+ subjectiveHeadInst : subjectiveHead ,
120
+ }
121
+
122
+ m .syncerReg , err = meter .RegisterCallback (m .observeMetrics , m .subjectiveHeadInst , m .syncLoopRunningInst )
36
123
if err != nil {
37
124
return nil , err
38
125
}
39
126
40
127
return m , nil
41
128
}
42
129
43
- // recordTotalSynced records the total amount of synced headers.
44
- func (m * metrics ) recordTotalSynced (totalSynced int ) {
130
+ func (m * metrics ) observeMetrics (_ context.Context , obs metric.Observer ) error {
131
+ obs .ObserveInt64 (m .subjectiveHeadInst , m .subjectiveHead .Load ())
132
+ obs .ObserveInt64 (m .syncLoopRunningInst , m .syncLoopActive .Load ())
133
+ return nil
134
+ }
135
+
136
+ func (m * metrics ) syncStarted (ctx context.Context ) {
137
+ m .observe (ctx , func (ctx context.Context ) {
138
+ m .syncStartedTs = time .Now ()
139
+ m .syncLoopStarted .Add (ctx , 1 )
140
+ m .syncLoopActive .Store (1 )
141
+ })
142
+ }
143
+
144
+ func (m * metrics ) syncFinished (ctx context.Context ) {
145
+ m .observe (ctx , func (ctx context.Context ) {
146
+ m .syncLoopActive .Store (0 )
147
+ m .syncLoopDurationHist .Record (ctx , time .Since (m .syncStartedTs ).Seconds ())
148
+ })
149
+ }
150
+
151
+ func (m * metrics ) unrecentHead (ctx context.Context ) {
152
+ m .observe (ctx , func (ctx context.Context ) {
153
+ m .unrecentHeader .Add (ctx , 1 )
154
+ })
155
+ }
156
+
157
+ func (m * metrics ) trustedPeersOutOufSync (ctx context.Context ) {
158
+ m .observe (ctx , func (ctx context.Context ) {
159
+ m .trustedPeersOutOfSync .Add (ctx , 1 )
160
+ })
161
+ }
162
+
163
+ func (m * metrics ) subjectiveInitialization (ctx context.Context ) {
164
+ m .observe (ctx , func (ctx context.Context ) {
165
+ m .subjectiveInit .Add (ctx , 1 )
166
+ })
167
+ }
168
+
169
+ func (m * metrics ) updateGetRangeRequestInfo (ctx context.Context , amount int , failed bool ) {
170
+ m .observe (ctx , func (ctx context.Context ) {
171
+ m .requestRangeTimeHist .Record (ctx , time .Since (m .requestRangeStartTs ).Seconds (),
172
+ metric .WithAttributes (
173
+ attribute .Int ("headers amount" , amount ),
174
+ attribute .Bool ("request failed" , failed ),
175
+ ))
176
+ })
177
+ }
178
+
179
+ func (m * metrics ) newSubjectiveHead (ctx context.Context , height uint64 , timestamp time.Time ) {
180
+ m .observe (ctx , func (ctx context.Context ) {
181
+ m .subjectiveHead .Store (int64 (height ))
182
+
183
+ if ! m .prevHeader .IsZero () {
184
+ m .blockTime .Record (ctx , timestamp .Sub (m .prevHeader ).Seconds ())
185
+ }
186
+ })
187
+ }
188
+
189
+ func (m * metrics ) rangeRequestStart () {
190
+ if m == nil {
191
+ return
192
+ }
193
+ m .requestRangeStartTs = time .Now ()
194
+ }
195
+
196
+ func (m * metrics ) rangeRequestStop () {
45
197
if m == nil {
46
198
return
47
199
}
200
+ m .requestRangeStartTs = time.Time {}
201
+ }
48
202
49
- m .totalSynced .Add (int64 (totalSynced ))
203
+ func (m * metrics ) observe (ctx context.Context , observeFn func (context.Context )) {
204
+ if m == nil {
205
+ return
206
+ }
207
+ if ctx .Err () != nil {
208
+ ctx = context .Background ()
209
+ }
210
+ observeFn (ctx )
211
+ }
212
+
213
+ func (m * metrics ) Close () error {
214
+ if m == nil {
215
+ return nil
216
+ }
217
+ return m .syncerReg .Unregister ()
50
218
}
0 commit comments