Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
30bc5ea
logs: analyzer-v2
iurii-ssv Aug 5, 2025
a4de2da
implement log parser(s) and add time_since_slot_start estimates
iurii-ssv Aug 5, 2025
9aa7d03
add error catching
iurii-ssv Aug 5, 2025
09b91ad
fix typos
iurii-ssv Aug 5, 2025
7f5dc08
committee-analyzer adjustments, some other minor adjustments
iurii-ssv Aug 6, 2025
dfdb268
add round-timeout to potentially interesting log to highlight
iurii-ssv Aug 6, 2025
32503e7
restructure duty analyzers and implement proposer-duty analyzer
iurii-ssv Aug 6, 2025
f9fb6a8
misc adjustments
iurii-ssv Aug 7, 2025
44ad6e9
fix log-entry timestamp parsing
iurii-ssv Aug 7, 2025
9a87ef0
better filtering for committee-duty
iurii-ssv Aug 7, 2025
d7ba021
add aggregator log analizer (v2)
iurii-ssv Aug 19, 2025
12ee09c
tmp
iurii-ssv Aug 20, 2025
9cb1c37
put back code classified as dead by accident
iurii-ssv Aug 20, 2025
78e19f7
greb by duty intent to execute
iurii-ssv Aug 20, 2025
739bfca
add more details, specifically about duty-fetching
iurii-ssv Aug 20, 2025
7df9634
improvements, + add sync committee contribution analyzer
iurii-ssv Aug 29, 2025
e232ebd
adjustments
iurii-ssv Aug 29, 2025
0fff0ae
add more lines to analyze, improve detection technique
iurii-ssv Aug 31, 2025
3db8c5d
latest adjustments
iurii-ssv Sep 1, 2025
3c05fe6
improve error/warn handling, rearrange duty filterers
iurii-ssv Sep 3, 2025
2cf53d7
improve errors-filtering
iurii-ssv Sep 4, 2025
4c3ec55
tmp
iurii-ssv Sep 11, 2025
cf4e9e1
support duty-id & rework existing rules for that
iurii-ssv Sep 11, 2025
6a1762a
adjustments
iurii-ssv Sep 11, 2025
0438a49
filter out irrelevant errors
iurii-ssv Sep 16, 2025
b17e678
add head-block arrived for committee duty
iurii-ssv Sep 23, 2025
f34aa2a
extend timestamp parsing to more formats
iurii-ssv Sep 24, 2025
3829341
adjustments
iurii-ssv Sep 26, 2025
017b7df
tmp
iurii-ssv Oct 29, 2025
400f28d
further improvements
iurii-ssv Oct 30, 2025
52ad653
tmp
iurii-ssv Nov 3, 2025
403c671
Merge branch 'main' into logs-analyzer-v2
iurii-ssv Nov 3, 2025
b46e05b
fix linter
iurii-ssv Nov 3, 2025
84c533d
add make format
iurii-ssv Nov 3, 2025
7f10724
cleanup
iurii-ssv Nov 3, 2025
97ba617
adjustments
iurii-ssv Nov 5, 2025
1721287
include slot-relevant lines by comparing the line time vs slot time
iurii-ssv Dec 15, 2025
d0aa5c7
clean up junk at the start of log-file(s) + use fmt.Print for better …
iurii-ssv Dec 18, 2025
6a5d666
get rid of logger for simple & clean output
iurii-ssv Dec 22, 2025
a72184a
minor adjustments
iurii-ssv Dec 22, 2025
28cf5a3
get rid of false-positives
iurii-ssv Dec 24, 2025
bfd5f46
cleanup & add some details to proposer-duty
iurii-ssv Dec 24, 2025
500e070
adjust maybeRelevantForSlot
iurii-ssv Dec 24, 2025
fc10027
cleanup & enrich commitee-duty summary printout
iurii-ssv Dec 24, 2025
cf10163
standardize & simplify
iurii-ssv Dec 24, 2025
4d7bd0b
misc improvements
iurii-ssv Dec 24, 2025
86f8052
tmpp
iurii-ssv Mar 26, 2026
14d2b00
highlight reorgs
iurii-ssv Apr 3, 2026
214d4fc
remove deprecated log-marker
iurii-ssv Apr 16, 2026
b0a222b
add relevant log-line
iurii-ssv Apr 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
version: "2"

run:
allow-parallel-runners: true

linters:
exclusions:
generated: lax
Expand All @@ -9,3 +11,9 @@ linters:
- common-false-positives
- legacy
- std-error-handling

settings:
staticcheck:
checks:
- all
- "-S1038"
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ run-benchmark: build
run-analyzer: build
@cd ${BINARY_DIR} && ./${BINARY_NAME} analyzer

.PHONY: log-analyzer-v2
log-analyzer-v2:
go run analyzer-v2/cmd/cmd.go

########## DOCKER
.PHONY: docker-build
docker-build:
Expand Down Expand Up @@ -57,6 +61,18 @@ dep:
vet:
go vet ./...

.PHONY: format
format:
# `goimports` doesn't support simplify option ("-s"), hence we run `gofmt` separately
# just for that - see https://github.com/golang/go/issues/21476 for details.
gofmt -s -w $$(find . -name '*.go' -not -path "*mock*")
# Formatters such as goimports do not deem necessary to "skip" generated code and
# rather want generators to generate code that complies with the desired formats
# (see https://github.com/golang/go/issues/71676 for details). In practice however
# it's not always possible to fix that on the generator side, so we have to use a
# work-around here to filter out generated files on our own.
$(RUN_TOOL) goimports -l -w -local github.com/ssvlabs/ssv-pulse/ $$(find . -name '*.go' -not -path "*mock*")

#https://github.com/golangci/golangci-lint/blob/HEAD/.golangci.reference.yml
.PHONY: lint
lint:
Expand Down
138 changes: 138 additions & 0 deletions analyzer-v2/cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package main

import (
"fmt"
"os"
"strings"

"github.com/sanity-io/litter"
"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/ssvlabs/ssv-pulse/analyzer-v2/config"
"github.com/ssvlabs/ssv-pulse/analyzer-v2/duties"
"github.com/ssvlabs/ssv-pulse/analyzer-v2/internal/environment"
)

const (
logFilesDirectoryFlag = "log-files-directory"
)

func init() {
CMD.Flags().String(logFilesDirectoryFlag, "", "Path to the directory containing SSV node log files for analysis, e.g. my-file-dir")

err := viper.BindPFlag("analyzer.log-files-directory", CMD.Flags().Lookup(logFilesDirectoryFlag))
if err != nil {
// TODO
panic(err)
}
}

func main() {
err := CMD.Execute()
if err != nil {
os.Exit(1)
}
os.Exit(0)
}

var CMD = &cobra.Command{
Use: "ssv-pulse-analyze-v2",
Short: "CLI for analyzing log files emitted by SSV node",
RunE: func(cmd *cobra.Command, args []string) error {
cfg, err := parseConfig()
if err != nil {
return fmt.Errorf("parse config: %w", err)
}

fmt.Println(fmt.Sprintf("config %s is loaded: %s", viper.ConfigFileUsed(), litter.Sdump(cfg)))
fmt.Println()

err = cfg.Validate()
if err != nil {
return fmt.Errorf("validate config: %w", err)
}

filesAll, err := os.ReadDir(cfg.LogFilesDirectory)
if err != nil {
return fmt.Errorf("could not read logs directory: %w", err)
}
filesLog := make([]os.DirEntry, 0, len(filesAll))
for _, file := range filesAll {
if file.IsDir() {
continue
}
if strings.HasSuffix(file.Name(), ".log") || strings.HasSuffix(file.Name(), ".logs") || strings.HasSuffix(file.Name(), ".txt") {
filesLog = append(filesLog, file)
}
}

if len(filesLog) == 0 {
return fmt.Errorf("no log files found in %s", cfg.LogFilesDirectory)
}

blockchain, err := environment.BlockchainByName(cfg.Blockchain)
if err != nil {
return fmt.Errorf("get blockchain by name: %w", err)
}

logParser, err := environment.LogParserByName(cfg.LogFormat)
if err != nil {
return fmt.Errorf("get log parser by name: %w", err)
}

if cfg.AnalyzeCommitteeDuty {
fmt.Println(fmt.Sprintf("analyzing COMMITTEE duty: target slot=%d, duty_id=%s", cfg.TargetSlot, cfg.DutyID))
a := duties.NewCommittee(blockchain, logParser)
err := duties.Analyze(a, cfg.LogFilesDirectory, filesLog, cfg.DutyID, cfg.TargetSlot)
if err != nil {
return fmt.Errorf("analyze proposer duty: %w", err)
}
}
if cfg.AnalyzeProposerDuty {
fmt.Println(fmt.Sprintf("analyzing PROPOSER duty: target slot=%d, duty_id=%s", cfg.TargetSlot, cfg.DutyID))
a := duties.NewProposer(blockchain, logParser)
err := duties.Analyze(a, cfg.LogFilesDirectory, filesLog, cfg.DutyID, cfg.TargetSlot)
if err != nil {
return fmt.Errorf("analyze proposer duty: %w", err)
}
}
if cfg.AnalyzeAggregatorDuty {
fmt.Println(fmt.Sprintf("analyzing AGGREGATOR duty: target slot=%d, duty_id=%s", cfg.TargetSlot, cfg.DutyID))
a := duties.NewAggregator(blockchain, logParser)
err := duties.Analyze(a, cfg.LogFilesDirectory, filesLog, cfg.DutyID, cfg.TargetSlot)
if err != nil {
return fmt.Errorf("analyze aggregator duty: %w", err)
}
}
if cfg.AnalyzeSyncCommitteeContribution {
fmt.Println(fmt.Sprintf("analyzing SYNC_COMMITTEE_CONTRIBUTION duty: target slot=%d, duty_id=%s", cfg.TargetSlot, cfg.DutyID))
a := duties.NewSyncCommitteeContribution(blockchain, logParser)
err := duties.Analyze(a, cfg.LogFilesDirectory, filesLog, cfg.DutyID, cfg.TargetSlot)
if err != nil {
return fmt.Errorf("analyze sync_committee_contribution duty: %w", err)
}
}

return nil
},
}

func parseConfig() (*config.Config, error) {
viper.SetConfigName("config.yaml")
viper.SetConfigType("yaml")

viper.AddConfigPath(".")
viper.AddConfigPath("./analyzer-v2/config")

var cfg config.Config

if err := viper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("read config: %w", err)
}
if err := viper.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("unmarshal config: %w", err)
}

return &cfg, nil
}
44 changes: 44 additions & 0 deletions analyzer-v2/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package config

import (
"fmt"

"github.com/attestantio/go-eth2-client/spec/phase0"
)

type Config struct {
LogFilesDirectory string `mapstructure:"log-files-directory"`

Blockchain string `mapstructure:"blockchain"`

LogFormat string `mapstructure:"log-format"`

AnalyzeCommitteeDuty bool `mapstructure:"analyze-committee-duty"`
AnalyzeProposerDuty bool `mapstructure:"analyze-proposer-duty"`
AnalyzeAggregatorDuty bool `mapstructure:"analyze-aggregator-duty"`
AnalyzeSyncCommitteeContribution bool `mapstructure:"analyze-sync-committee-contribution-duty"`

DutyID string `mapstructure:"duty-id"`
TargetSlot phase0.Slot `mapstructure:"target-slot"`
}

func (c *Config) Validate() error {
if c.LogFilesDirectory == "" {
return fmt.Errorf("❕ 'log-files-directory' was not specified")
}
if c.Blockchain == "" {
return fmt.Errorf("❕ 'blockchain' was not specified")
}
if c.LogFormat == "" {
return fmt.Errorf("❕ 'log-format' was not specified")
}
if c.DutyID == "" && c.TargetSlot == 0 {
return fmt.Errorf("❕ at least one of `duty-id`, 'target-slot' must be specified")
}

if !c.AnalyzeCommitteeDuty && !c.AnalyzeProposerDuty && !c.AnalyzeAggregatorDuty && !c.AnalyzeSyncCommitteeContribution {
return fmt.Errorf("❕ must specify at least 1 duty analyzer")
}

return nil
}
35 changes: 35 additions & 0 deletions analyzer-v2/config/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
log-files-directory: /Users/iurii/Downloads/target
#log-files-directory: /Users/iurii/Downloads/p2p
#log-files-directory: /Users/iurii/Downloads/hashkey
#log-files-directory: /Users/iurii/Downloads/kraken

blockchain: hoodi
#blockchain: mainnet

log-format: standard
#log-format: external

#analyze-committee-duty: true
analyze-committee-duty: false
analyze-proposer-duty: true
#analyze-proposer-duty: false

#analyze-aggregator-duty: true
analyze-aggregator-duty: false
#analyze-sync-committee-contribution-duty: true
analyze-sync-committee-contribution-duty: false

#duty-id: COMMITTEE-1_2_3_4-e415902-s13308893
#duty-id: COMMITTEE-1_2_3_4-
#duty-id: COMMITTEE-53_54_55_56-
#duty-id: COMMITTEE-1_2_417_418-e50846-s1627077
#
target-slot: 2845052








Loading
Loading