Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
102 changes: 57 additions & 45 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,54 +1,66 @@
---
output:
sort-results: true

version: "2"
linters:
enable:
- depguard
- gocritic
- gofumpt
- goimports
- revive
- misspell
- revive
- unconvert
- unused
- wsl

settings:
depguard:
rules:
main:
files:
- $all
deny:
- pkg: github.com/sirupsen/logrus
desc: Not allowed
- pkg: github.com/pkg/errors
desc: Should be replaced by standard lib errors package
- pkg: sync/atomic
desc: Use go.uber.org/atomic instead of sync/atomic
- pkg: io/ioutil
desc: Use corresponding 'os' or 'io' functions instead.
errcheck:
exclude-functions:
- io.Copy
- io.WriteString
- (net/http.ResponseWriter).Write
- (*net/http.Server).Shutdown
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- gocritic
text: appendAssign
- linters:
- errcheck
path: _test.go
paths:
- third_party$
- builtin$
- examples$
issues:
max-same-issues: 0
exclude-rules:
- linters:
- gocritic
text: "appendAssign"
- path: _test.go
linters:
- errcheck

linters-settings:
depguard:
rules:
main:
files:
- $all
deny:
- pkg: "github.com/sirupsen/logrus"
desc: Not allowed
- pkg: "github.com/pkg/errors"
desc: Should be replaced by standard lib errors package
- pkg: "sync/atomic"
desc: Use go.uber.org/atomic instead of sync/atomic
- pkg: "io/ioutil"
desc: Use corresponding 'os' or 'io' functions instead.
errcheck:
exclude-functions:
# Don't flag lines such as "io.Copy(io.Discard, resp.Body)".
- io.Copy
# The next two are used in HTTP handlers, any error is handled by the server itself.
- io.WriteString
- (net/http.ResponseWriter).Write
# No need to check for errors on server's shutdown.
- (*net/http.Server).Shutdown
goimports:
local-prefixes: github.com/prometheus/prometheus
gofumpt:
extra-rules: true
formatters:
enable:
- gofumpt
- goimports
settings:
gofumpt:
extra-rules: true
goimports:
local-prefixes:
- github.com/prometheus/prometheus
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
70 changes: 47 additions & 23 deletions cmd/relayer_exporter/relayer_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,64 @@ func getVersion() string {

// refreshCollectors updates the collectors with new configuration
func refreshCollectors(ctx context.Context, cfg *config.Config, registry *prometheus.Registry) error {
paths, err := cfg.IBCPaths(ctx)
err := refreshIBCCollector(ctx, cfg, registry)
if err != nil {
return fmt.Errorf("failed to get IBC paths: %w", err)
return err
}

rpcs, err := cfg.GetRPCsMap()
err = refreshWalletBalanceCollector(cfg, registry)
if err != nil {
return fmt.Errorf("failed to get RPCs map: %w", err)
return err
}

// Unregister existing collectors
registry.Unregister(collector.IBCCollector{})
registry.Unregister(collector.WalletBalanceCollector{})
return nil
}

// Create and register new collectors
ibcCollector := collector.IBCCollector{
RPCs: rpcs,
Paths: paths,
func refreshWalletBalanceCollector(cfg *config.Config, registry *prometheus.Registry) error {
if len(cfg.Accounts) == 0 {
log.Warn("No accounts configured, skipping wallet balance collector refresh")
return nil
}

rpcs := cfg.GetRPCsMap()
// Unregister existing collectors
registry.Unregister(collector.WalletBalanceCollector{})

// Create and register new collector
balancesCollector := collector.WalletBalanceCollector{
RPCs: rpcs,
Accounts: cfg.Accounts,
}

registry.MustRegister(ibcCollector)
registry.MustRegister(balancesCollector)

return nil
}

// refreshIBCCollectors updates the IBC collector with new paths
func refreshIBCCollector(ctx context.Context, cfg *config.Config, registry *prometheus.Registry) error {
paths, err := cfg.IBCPaths(ctx)
if err != nil {
log.Warn("Failed to get IBC paths, skipping IBC collector refresh", zap.Error(err))
return nil
}

if len(paths) > 0 {
rpcs := cfg.GetRPCsMap()
// Unregister existing collector
registry.Unregister(collector.IBCCollector{})

// Create and register new collector
ibcCollector := collector.IBCCollector{
RPCs: rpcs,
Paths: paths,
}
registry.MustRegister(ibcCollector)
}

return nil
}

func main() {
port := flag.Int("p", 8008, "Server port")
version := flag.Bool("version", false, "Print version")
Expand All @@ -83,19 +110,8 @@ func main() {
log.Fatal(err.Error())
}

log.Info(
fmt.Sprintf(
"Github IBC registry: %s/%s",
cfg.GitHub.Org,
cfg.GitHub.Repo,
),
zap.String("Mainnet Directory", cfg.GitHub.IBCDir),
zap.String("Testnet Directory", cfg.GitHub.TestnetsIBCDir),
)

// Create a context with cancel
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // Ensure context is cancelled when main exits

// Setup signal handling for graceful shutdown
sigChan := make(chan os.Signal, 1)
Expand All @@ -108,12 +124,17 @@ func main() {
log.Fatal(err.Error())
}

// Defer cancel after all fatal errors
defer cancel() // Ensure context is cancelled when main exits

// Start periodic refresh in background
var wg sync.WaitGroup

wg.Add(1)

go func() {
defer wg.Done()

ticker := time.NewTicker(*refreshInterval)
defer ticker.Stop()

Expand All @@ -124,10 +145,12 @@ func main() {
return
case <-ticker.C:
log.Info("Refreshing configuration and collectors")

if err := refreshCollectors(ctx, cfg, registry); err != nil {
log.Error(fmt.Sprintf("Failed to refresh collectors: %v", err))
continue
}

log.Info("Successfully refreshed configuration and collectors")
}
}
Expand All @@ -147,6 +170,7 @@ func main() {
go func() {
log.Info(fmt.Sprintf("Starting server on addr: %s", server.Addr))
log.Info(fmt.Sprintf("Configuration refresh interval: %s", refreshInterval.String()))

if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(fmt.Sprintf("Server error: %v", err))
}
Expand Down
2 changes: 1 addition & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ rpc:
url: https://rpc.planq.network:443
- chainName: passage
chainId: passage-2
url: https://passage-rpc.staketab.org:443
url: https://passage-rpc.polkachu.com:443
- chainName: sentinel
chainId: sentinelhub-2
url: https://rpc-sentinel.chainvibes.com:443
Expand Down
33 changes: 28 additions & 5 deletions pkg/collector/wallet_balance_collector.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package collector

import (
"context"
"math/big"
"strings"
"sync"

"github.com/prometheus/client_golang/prometheus"
"go.uber.org/zap"

"github.com/archway-network/relayer_exporter/pkg/chain"
"github.com/archway-network/relayer_exporter/pkg/config"
log "github.com/archway-network/relayer_exporter/pkg/logger"
)
Expand All @@ -18,12 +21,12 @@ const (
var walletBalance = prometheus.NewDesc(
walletBalanceMetricName,
"Returns wallet balance for an address on a chain.",
[]string{"account", "chain_id", "denom", "status"}, nil,
[]string{"account", "chain_id", "denom", "status", "tags"}, nil,
)

type WalletBalanceCollector struct {
RPCs *map[string]config.RPC
Accounts []config.Account
Accounts []*config.Account
}

func (wb WalletBalanceCollector) Describe(ch chan<- *prometheus.Desc) {
Expand All @@ -44,7 +47,7 @@ func (wb WalletBalanceCollector) Collect(ch chan<- prometheus.Metric) {
balance := 0.0
status := successStatus

err := account.GetBalance(ctx, wb.RPCs)
err := getBalance(ctx, &account, wb.RPCs)
if err != nil {
status = errorStatus

Expand All @@ -58,12 +61,32 @@ func (wb WalletBalanceCollector) Collect(ch chan<- prometheus.Metric) {
walletBalance,
prometheus.GaugeValue,
balance,
[]string{account.Address, (*wb.RPCs)[account.ChainName].ChainID, account.Denom, status}...,
[]string{account.Address, (*wb.RPCs)[account.ChainName].ChainID, account.Denom, status, strings.Join(account.Tags, ",")}...,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tags must defineable in the configs e.g.

accounts:
  - address: archway1avwvqzu9gv86g5fxx5p2xqe0w33wklt27jusdrhszwccnfnxx0rsmzz8nu
    chainName: archway
    denom: aarch
    tags: tag1,tag2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my bad, it expect a list of strings

accounts:

  • address: archway1avwvqzu9gv86g5fxx5p2xqe0w33wklt27jusdrhszwccnfnxx0rsmzz8nu
    chainName: archway
    denom: aarch
    tags: ["tag1","tag2"]

)
}(a)
}(*a)
}

wg.Wait()

log.Debug("Stop collecting", zap.String("metric", walletBalanceMetricName))
}

func getBalance(ctx context.Context, a *config.Account, rpcs *map[string]config.RPC) error {
chain, err := chain.PrepChain(ctx, chain.Info{
ChainID: (*rpcs)[a.ChainName].ChainID,
RPCAddr: (*rpcs)[a.ChainName].URL,
Timeout: (*rpcs)[a.ChainName].Timeout,
})
if err != nil {
return err
}

coins, err := chain.ChainProvider.QueryBalanceWithAddress(ctx, a.Address)
if err != nil {
return err
}

a.Balance = coins.AmountOf(a.Denom)

return nil
}
Loading
Loading