From 14427484b9bde6dcfcddcde8268622bf1fc6a443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Lehtim=C3=A4ki?= Date: Tue, 14 Nov 2023 16:44:56 +0200 Subject: [PATCH] feat: add discord labels to metrics (#26) * feat: add discord labels to metrics * feat: only accept digits in discord ids * feat: add testcases for getDiscordIDs * fix: linting error * feat: add more descriptive test case --- go.mod | 2 +- pkg/collector/collector.go | 51 +++++++++++++++++++++--- pkg/collector/collector_test.go | 64 ++++++++++++++++++++++++++++++ pkg/config/config.go | 69 +++++++++++++++++++++++++++++---- pkg/ibc/ibc.go | 4 +- 5 files changed, 174 insertions(+), 16 deletions(-) create mode 100644 pkg/collector/collector_test.go diff --git a/go.mod b/go.mod index 0e909d7..5b329fa 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 require ( cosmossdk.io/math v1.0.1 github.com/caarlos0/env/v9 v9.0.0 + github.com/cosmos/ibc-go/v7 v7.2.0 github.com/cosmos/relayer/v2 v2.4.1 github.com/google/go-github/v55 v55.0.0 github.com/prometheus/client_golang v1.15.0 @@ -56,7 +57,6 @@ require ( github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/gogoproto v1.4.10 // indirect github.com/cosmos/iavl v0.20.0 // indirect - github.com/cosmos/ibc-go/v7 v7.2.0 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect diff --git a/pkg/collector/collector.go b/pkg/collector/collector.go index 5454ae9..fcf4043 100644 --- a/pkg/collector/collector.go +++ b/pkg/collector/collector.go @@ -4,9 +4,10 @@ import ( "fmt" "math/big" "reflect" + "regexp" + "strings" "sync" - "github.com/cosmos/relayer/v2/relayer" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" @@ -27,7 +28,14 @@ var ( clientExpiry = prometheus.NewDesc( clientExpiryMetricName, "Returns light client expiry in unixtime.", - []string{"host_chain_id", "client_id", "target_chain_id", "status"}, nil, + []string{ + "host_chain_id", + "client_id", + "target_chain_id", + "discord_ids", + "status", + }, + nil, ) channelStuckPackets = prometheus.NewDesc( channelStuckPacketsMetricName, @@ -37,6 +45,7 @@ var ( "dst_channel_id", "src_chain_id", "dst_chain_id", + "discord_ids", "status", }, nil, @@ -50,7 +59,7 @@ var ( type IBCCollector struct { RPCs *map[string]config.RPC - Paths []*relayer.IBCdata + Paths []*config.IBCData } type WalletBalanceCollector struct { @@ -77,9 +86,11 @@ func (cc IBCCollector) Collect(ch chan<- prometheus.Metric) { for _, p := range cc.Paths { wg.Add(1) - go func(path *relayer.IBCdata) { + go func(path *config.IBCData) { defer wg.Done() + discordIDs := getDiscordIDs(path.Operators) + // Client info ci, err := ibc.GetClientsInfo(path, cc.RPCs) status := successStatus @@ -94,14 +105,26 @@ func (cc IBCCollector) Collect(ch chan<- prometheus.Metric) { clientExpiry, prometheus.GaugeValue, float64(ci.ChainAClientExpiration.Unix()), - []string{(*cc.RPCs)[path.Chain1.ChainName].ChainID, path.Chain1.ClientID, (*cc.RPCs)[path.Chain2.ChainName].ChainID, status}..., + []string{ + (*cc.RPCs)[path.Chain1.ChainName].ChainID, + path.Chain1.ClientID, + (*cc.RPCs)[path.Chain2.ChainName].ChainID, + discordIDs, + status, + }..., ) ch <- prometheus.MustNewConstMetric( clientExpiry, prometheus.GaugeValue, float64(ci.ChainBClientExpiration.Unix()), - []string{(*cc.RPCs)[path.Chain2.ChainName].ChainID, path.Chain2.ClientID, (*cc.RPCs)[path.Chain1.ChainName].ChainID, status}..., + []string{ + (*cc.RPCs)[path.Chain2.ChainName].ChainID, + path.Chain2.ClientID, + (*cc.RPCs)[path.Chain1.ChainName].ChainID, + discordIDs, + status, + }..., ) // Stuck packets @@ -125,6 +148,7 @@ func (cc IBCCollector) Collect(ch chan<- prometheus.Metric) { sp.Destination, (*cc.RPCs)[path.Chain1.ChainName].ChainID, (*cc.RPCs)[path.Chain2.ChainName].ChainID, + discordIDs, status, }..., ) @@ -138,6 +162,7 @@ func (cc IBCCollector) Collect(ch chan<- prometheus.Metric) { sp.Source, (*cc.RPCs)[path.Chain2.ChainName].ChainID, (*cc.RPCs)[path.Chain1.ChainName].ChainID, + discordIDs, status, }..., ) @@ -192,3 +217,17 @@ func (wb WalletBalanceCollector) Collect(ch chan<- prometheus.Metric) { log.Debug("Stop collecting", zap.String("metric", walletBalanceMetricName)) } + +func getDiscordIDs(ops []config.Operator) string { + var ids []string + + pattern := regexp.MustCompile(`^\d+$`) + + for _, op := range ops { + if pattern.MatchString(op.Discord.ID) { + ids = append(ids, op.Discord.ID) + } + } + + return strings.Join(ids, ",") +} diff --git a/pkg/collector/collector_test.go b/pkg/collector/collector_test.go new file mode 100644 index 0000000..d8a0de1 --- /dev/null +++ b/pkg/collector/collector_test.go @@ -0,0 +1,64 @@ +package collector + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/archway-network/relayer_exporter/pkg/config" +) + +func TestDiscordIDs(t *testing.T) { + testCases := []struct { + name string + ops []config.Operator + expected string + }{ + { + name: "All Valid IDs", + ops: []config.Operator{ + { + Discord: config.Discord{ID: "123456"}, + }, + { + Discord: config.Discord{ID: "12312387"}, + }, + }, + expected: "123456,12312387", + }, + { + name: "Some Invalid IDs", + ops: []config.Operator{ + { + Discord: config.Discord{ID: "123456"}, + }, + { + Discord: config.Discord{ID: "ABCDEF"}, + }, + { + Discord: config.Discord{ID: "789012"}, + }, + }, + expected: "123456,789012", + }, + { + name: "No Valid IDs", + ops: []config.Operator{ + {Discord: config.Discord{ID: "ABCDEF"}}, + {Discord: config.Discord{ID: "GHIJKL"}}, + }, + expected: "", + }, + { + name: "Empty Input", + ops: []config.Operator{{}, {}, {}}, + expected: "", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res := getDiscordIDs(tc.ops) + assert.Equal(t, tc.expected, res) + }) + } +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 0489b23..c1a00de 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -9,7 +9,6 @@ import ( "cosmossdk.io/math" "github.com/caarlos0/env/v9" - "github.com/cosmos/relayer/v2/relayer" "github.com/google/go-github/v55/github" "gopkg.in/yaml.v3" @@ -46,6 +45,56 @@ type Config struct { } `yaml:"github"` } +type IBCData struct { + Schema string `json:"$schema"` + Chain1 struct { + ChainName string `json:"chain_name"` + ClientID string `json:"client_id"` + ConnectionID string `json:"connection_id"` + } `json:"chain_1"` + Chain2 struct { + ChainName string `json:"chain_name"` + ClientID string `json:"client_id"` + ConnectionID string `json:"connection_id"` + } `json:"chain_2"` + Channels []struct { + Chain1 struct { + ChannelID string `json:"channel_id"` + PortID string `json:"port_id"` + } `json:"chain_1"` + Chain2 struct { + ChannelID string `json:"channel_id"` + PortID string `json:"port_id"` + } `json:"chain_2"` + Ordering string `json:"ordering"` + Version string `json:"version"` + Tags struct { + Status string `json:"status"` + Preferred bool `json:"preferred"` + Dex string `json:"dex"` + Properties string `json:"properties"` + } `json:"tags,omitempty"` + } `json:"channels"` + Operators []Operator `json:"operators"` +} + +type Operator struct { + Chain1 struct { + Address string `json:"address"` + } `json:"chain_1"` + Chain2 struct { + Address string `json:"address"` + } `json:"chain_2"` + Memo string `json:"memo"` + Name string `json:"name"` + Discord Discord `json:"discord"` +} + +type Discord struct { + Handle string `json:"handle"` + ID string `json:"id"` +} + func (a *Account) GetBalance(rpcs *map[string]RPC) error { chain, err := chain.PrepChain(chain.Info{ ChainID: (*rpcs)[a.ChainName].ChainID, @@ -77,7 +126,7 @@ func (c *Config) GetRPCsMap() *map[string]RPC { return &rpcs } -func (c *Config) IBCPaths() ([]*relayer.IBCdata, error) { +func (c *Config) IBCPaths() ([]*IBCData, error) { client := github.NewClient(nil) if c.GitHub.Token != "" { @@ -91,7 +140,7 @@ func (c *Config) IBCPaths() ([]*relayer.IBCdata, error) { return nil, err } - testnetsPaths := []*relayer.IBCdata{} + testnetsPaths := []*IBCData{} if c.GitHub.TestnetsIBCDir != "" { testnetsPaths, err = c.getPaths(c.GitHub.TestnetsIBCDir, client) if err != nil { @@ -104,7 +153,7 @@ func (c *Config) IBCPaths() ([]*relayer.IBCdata, error) { return paths, nil } -func (c *Config) getPaths(dir string, client *github.Client) ([]*relayer.IBCdata, error) { +func (c *Config) getPaths(dir string, client *github.Client) ([]*IBCData, error) { if client == nil { return nil, ErrGitHubClient } @@ -116,16 +165,22 @@ func (c *Config) getPaths(dir string, client *github.Client) ([]*relayer.IBCdata return nil, err } - ibcs := []*relayer.IBCdata{} + ibcs := []*IBCData{} for _, file := range ibcDir { if strings.HasSuffix(*file.Path, ibcPathSuffix) { - content, _, _, err := client.Repositories.GetContents(ctx, c.GitHub.Org, c.GitHub.Repo, *file.Path, nil) + content, _, _, err := client.Repositories.GetContents( + ctx, + c.GitHub.Org, + c.GitHub.Repo, + *file.Path, + nil, + ) if err != nil { return nil, err } - ibc := &relayer.IBCdata{} + ibc := &IBCData{} c, err := content.GetContent() if err != nil { diff --git a/pkg/ibc/ibc.go b/pkg/ibc/ibc.go index b287c33..e8c4fda 100644 --- a/pkg/ibc/ibc.go +++ b/pkg/ibc/ibc.go @@ -39,7 +39,7 @@ type Channel struct { } } -func GetClientsInfo(ibc *relayer.IBCdata, rpcs *map[string]config.RPC) (ClientsInfo, error) { +func GetClientsInfo(ibc *config.IBCData, rpcs *map[string]config.RPC) (ClientsInfo, error) { clientsInfo := ClientsInfo{} cdA := chain.Info{ @@ -91,7 +91,7 @@ func GetClientsInfo(ibc *relayer.IBCdata, rpcs *map[string]config.RPC) (ClientsI return clientsInfo, nil } -func GetChannelsInfo(ibc *relayer.IBCdata, rpcs *map[string]config.RPC) (ChannelsInfo, error) { +func GetChannelsInfo(ibc *config.IBCData, rpcs *map[string]config.RPC) (ChannelsInfo, error) { ctx := context.Background() channelInfo := ChannelsInfo{}