Skip to content

Commit cce1521

Browse files
authored
Merge pull request #26 from Arkiv-Network/scx1332/metrics
Add metrics
2 parents e47cd74 + 88834dd commit cce1521

3 files changed

Lines changed: 110 additions & 24 deletions

File tree

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ require (
1919
cel.dev/expr v0.24.0 // indirect
2020
filippo.io/edwards25519 v1.1.0 // indirect
2121
github.com/Masterminds/semver/v3 v3.4.0 // indirect
22+
github.com/StackExchange/wmi v1.2.1 // indirect
2223
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
2324
github.com/bits-and-blooms/bitset v1.24.2 // indirect
2425
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
@@ -27,6 +28,7 @@ require (
2728
github.com/dustin/go-humanize v1.0.1 // indirect
2829
github.com/fatih/structtag v1.2.0 // indirect
2930
github.com/go-logr/logr v1.4.3 // indirect
31+
github.com/go-ole/go-ole v1.3.0 // indirect
3032
github.com/go-sql-driver/mysql v1.9.3 // indirect
3133
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
3234
github.com/google/cel-go v0.26.1 // indirect
@@ -53,11 +55,14 @@ require (
5355
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
5456
github.com/riza-io/grpc-go v0.2.0 // indirect
5557
github.com/russross/blackfriday/v2 v2.1.0 // indirect
58+
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
5659
github.com/spf13/cobra v1.9.1 // indirect
5760
github.com/spf13/pflag v1.0.7 // indirect
5861
github.com/sqlc-dev/sqlc v1.30.0 // indirect
5962
github.com/stoewer/go-strcase v1.2.0 // indirect
6063
github.com/tetratelabs/wazero v1.9.0 // indirect
64+
github.com/tklauser/go-sysconf v0.3.12 // indirect
65+
github.com/tklauser/numcpus v0.6.1 // indirect
6166
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 // indirect
6267
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect
6368
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect

go.sum

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1
99
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
1010
github.com/RoaringBitmap/roaring/v2 v2.14.4 h1:4aKySrrg9G/5oRtJ3TrZLObVqxgQ9f1znCRBwEwjuVw=
1111
github.com/RoaringBitmap/roaring/v2 v2.14.4/go.mod h1:oMvV6omPWr+2ifRdeZvVJyaz+aoEUopyv5iH0u/+wbY=
12+
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
13+
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
1214
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
1315
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
1416
github.com/alecthomas/participle/v2 v2.1.4 h1:W/H79S8Sat/krZ3el6sQMvMaahJ+XcM9WSI2naI7w2U=
@@ -44,6 +46,9 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
4446
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
4547
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
4648
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
49+
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
50+
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
51+
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
4752
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
4853
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
4954
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
@@ -132,6 +137,8 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR
132137
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
133138
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
134139
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
140+
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
141+
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
135142
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
136143
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
137144
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -158,6 +165,10 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
158165
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
159166
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
160167
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
168+
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
169+
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
170+
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
171+
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
161172
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
162173
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
163174
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 h1:mJdDDPblDfPe7z7go8Dvv1AJQDI3eQ/5xith3q2mFlo=
@@ -211,7 +222,11 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
211222
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
212223
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
213224
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
225+
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
226+
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
214227
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
228+
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
229+
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
215230
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
216231
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
217232
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

sqlitestore.go

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/Arkiv-Network/sqlite-bitmap-store/store"
1616
"github.com/ethereum/go-ethereum/common"
17+
"github.com/ethereum/go-ethereum/metrics"
1718
"github.com/golang-migrate/migrate/v4"
1819
"github.com/golang-migrate/migrate/v4/database/sqlite3"
1920
"github.com/golang-migrate/migrate/v4/source/iofs"
@@ -23,6 +24,21 @@ import (
2324
"github.com/Arkiv-Network/arkiv-events/events"
2425
)
2526

27+
var (
28+
// Metrics for tracking operations
29+
metricOperationStarted = metrics.NewRegisteredCounter("arkiv_store/operations_started", nil)
30+
metricOperationSuccessful = metrics.NewRegisteredCounter("arkiv_store/operations_successful", nil)
31+
metricCreates = metrics.NewRegisteredCounter("arkiv_store/creates", nil)
32+
metricUpdates = metrics.NewRegisteredCounter("arkiv_store/updates", nil)
33+
metricDeletes = metrics.NewRegisteredCounter("arkiv_store/deletes", nil)
34+
metricExtends = metrics.NewRegisteredCounter("arkiv_store/extends", nil)
35+
metricOwnerChanges = metrics.NewRegisteredCounter("arkiv_store/owner_changes", nil)
36+
// Tracks operation duration (ms) using an exponential decay sample so the histogram
37+
// is more responsive to recent performance by weighting newer measurements higher
38+
// (sample size 100, alpha 0.4).
39+
metricOperationTime = metrics.NewRegisteredHistogram("arkiv_store/operation_time_ms", nil, metrics.NewExpDecaySample(100, 0.4))
40+
)
41+
2642
type SQLiteStore struct {
2743
writePool *sql.DB
2844
readPool *sql.DB
@@ -99,18 +115,23 @@ func (s *SQLiteStore) GetLastBlock(ctx context.Context) (uint64, error) {
99115
return store.New(s.writePool).GetLastBlock(ctx)
100116
}
101117

118+
type blockStats struct {
119+
creates int
120+
updates int
121+
deletes int
122+
extends int
123+
ownerChanges int
124+
}
125+
102126
func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.BatchIterator) error {
103127

104128
for batch := range iterator {
105129
if batch.Error != nil {
106130
return fmt.Errorf("failed to follow events: %w", batch.Error)
107131
}
108132

109-
totalCreates := 0
110-
totalUpdates := 0
111-
totalDeletes := 0
112-
totalExtends := 0
113-
totalOwnerChanges := 0
133+
// We will calculate totals for the log at the end, but track per-block for metrics
134+
stats := make(map[uint64]*blockStats)
114135

115136
err := func() error {
116137

@@ -138,20 +159,22 @@ func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.Bat
138159

139160
startTime := time.Now()
140161

162+
metricOperationStarted.Inc(1)
163+
141164
mainLoop:
142165
for _, block := range batch.Batch.Blocks {
143166

144-
updates := 0
145-
deletes := 0
146-
extends := 0
147-
creates := 0
148-
ownerChanges := 0
149-
150167
if block.Number <= uint64(lastBlockFromDB) {
151168
s.log.Info("skipping block", "block", block.Number, "lastBlockFromDB", lastBlockFromDB)
152169
continue mainLoop
153170
}
154171

172+
// Initialize stats for this block
173+
if _, ok := stats[block.Number]; !ok {
174+
stats[block.Number] = &blockStats{}
175+
}
176+
blockStat := stats[block.Number]
177+
155178
updatesMap := map[common.Hash][]*events.OPUpdate{}
156179

157180
for _, operation := range block.Operations {
@@ -162,15 +185,14 @@ func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.Bat
162185
}
163186
}
164187

165-
// blockNumber := block.Number
166188
operationLoop:
167189
for _, operation := range block.Operations {
168190

169191
switch {
170192

171193
case operation.Create != nil:
172194
// expiresAtBlock := blockNumber + operation.Create.BTL
173-
creates++
195+
blockStat.creates++
174196
key := operation.Create.Key
175197

176198
stringAttributes := maps.Clone(operation.Create.StringAttributes)
@@ -225,14 +247,14 @@ func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.Bat
225247
}
226248
}
227249
case operation.Update != nil:
228-
updates++
229250

230251
updates := updatesMap[operation.Update.Key]
231252
lastUpdate := updates[len(updates)-1]
232253

233254
if operation.Update != lastUpdate {
234255
continue operationLoop
235256
}
257+
blockStat.updates++
236258

237259
key := operation.Update.Key.Bytes()
238260

@@ -319,7 +341,7 @@ func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.Bat
319341

320342
case operation.Delete != nil || operation.Expire != nil:
321343

322-
deletes++
344+
blockStat.deletes++
323345
var key []byte
324346
if operation.Delete != nil {
325347
key = common.Hash(*operation.Delete).Bytes()
@@ -363,7 +385,7 @@ func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.Bat
363385

364386
case operation.ExtendBTL != nil:
365387

366-
extends++
388+
blockStat.extends++
367389

368390
key := operation.ExtendBTL.Key.Bytes()
369391

@@ -403,7 +425,7 @@ func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.Bat
403425
}
404426

405427
case operation.ChangeOwner != nil:
406-
ownerChanges++
428+
blockStat.ownerChanges++
407429
key := operation.ChangeOwner.Key.Bytes()
408430

409431
latestPayload, err := st.GetPayloadForEntityKey(ctx, key)
@@ -449,12 +471,8 @@ func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.Bat
449471

450472
}
451473

452-
s.log.Info("block updated", "block", block.Number, "creates", creates, "updates", updates, "deletes", deletes, "extends", extends, "ownerChanges", ownerChanges)
453-
totalCreates += creates
454-
totalUpdates += updates
455-
totalDeletes += deletes
456-
totalExtends += extends
457-
totalOwnerChanges += ownerChanges
474+
// Log per block if needed, but we can now rely on the map for totals later
475+
s.log.Info("block updated", "block", block.Number, "creates", blockStat.creates, "updates", blockStat.updates, "deletes", blockStat.deletes, "extends", blockStat.extends, "ownerChanges", blockStat.ownerChanges)
458476
}
459477

460478
err = st.UpsertLastBlock(ctx, lastBlock)
@@ -472,7 +490,55 @@ func (s *SQLiteStore) FollowEvents(ctx context.Context, iterator arkivevents.Bat
472490
return fmt.Errorf("failed to commit transaction: %w", err)
473491
}
474492

475-
s.log.Info("batch processed", "firstBlock", firstBlock, "lastBlock", lastBlock, "processingTime", time.Since(startTime).Milliseconds(), "creates", totalCreates, "updates", totalUpdates, "deletes", totalDeletes, "extends", totalExtends, "ownerChanges", totalOwnerChanges)
493+
// Calculate batch totals for logging and update metrics PER BLOCK
494+
var (
495+
totalCreates int
496+
totalUpdates int
497+
totalDeletes int
498+
totalExtends int
499+
totalOwnerChanges int
500+
)
501+
502+
// Iterate blocks again to preserve order and update metrics per block
503+
for _, block := range batch.Batch.Blocks {
504+
if stat, ok := stats[block.Number]; ok {
505+
totalCreates += stat.creates
506+
totalUpdates += stat.updates
507+
totalDeletes += stat.deletes
508+
totalExtends += stat.extends
509+
totalOwnerChanges += stat.ownerChanges
510+
511+
// Update metrics specifically per block
512+
if stat.creates > 0 {
513+
metricCreates.Inc(int64(stat.creates))
514+
}
515+
if stat.updates > 0 {
516+
metricUpdates.Inc(int64(stat.updates))
517+
}
518+
if stat.deletes > 0 {
519+
metricDeletes.Inc(int64(stat.deletes))
520+
}
521+
if stat.extends > 0 {
522+
metricExtends.Inc(int64(stat.extends))
523+
}
524+
if stat.ownerChanges > 0 {
525+
metricOwnerChanges.Inc(int64(stat.ownerChanges))
526+
}
527+
}
528+
}
529+
530+
metricOperationSuccessful.Inc(1)
531+
metricOperationTime.Update(time.Since(startTime).Milliseconds())
532+
533+
s.log.Info("batch processed",
534+
"firstBlock", firstBlock,
535+
"lastBlock", lastBlock,
536+
"processingTime", time.Since(startTime).Milliseconds(),
537+
"creates", totalCreates,
538+
"updates", totalUpdates,
539+
"deletes", totalDeletes,
540+
"extends", totalExtends,
541+
"ownerChanges", totalOwnerChanges)
476542

477543
return nil
478544
}()

0 commit comments

Comments
 (0)