From e55c85e8110ee56098f87fdd36bf8d59a9995eb1 Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Wed, 14 Oct 2020 12:49:48 +0300 Subject: [PATCH 01/15] Add default flags for http and metrics --- cmd/root.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index eaad07568..45cdcb08c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -101,6 +101,11 @@ func init() { rootCmd.PersistentFlags().String("eth-network-id", "1", "eth network id") rootCmd.PersistentFlags().String("eth-chain-id", "1", "eth chain id") + rootCmd.PersistentFlags().String("http-addr", "127.0.0.1", "http host") + rootCmd.PersistentFlags().String("http-port", "8080", "http port") + + rootCmd.PersistentFlags().Bool("metrics", false, "enable metrics") + // and their .toml config bindings viper.BindPFlag("database.name", rootCmd.PersistentFlags().Lookup("database-name")) viper.BindPFlag("database.port", rootCmd.PersistentFlags().Lookup("database-port")) @@ -116,6 +121,11 @@ func init() { viper.BindPFlag("ethereum.genesisBlock", rootCmd.PersistentFlags().Lookup("eth-genesis-block")) viper.BindPFlag("ethereum.networkID", rootCmd.PersistentFlags().Lookup("eth-network-id")) viper.BindPFlag("ethereum.chainID", rootCmd.PersistentFlags().Lookup("eth-chain-id")) + + viper.BindPFlag("http.addr", rootCmd.PersistentFlags().Lookup("http-addr")) + viper.BindPFlag("http.port", rootCmd.PersistentFlags().Lookup("http-port")) + + viper.BindPFlag("metrics", rootCmd.PersistentFlags().Lookup("metrics")) } func initConfig() { From b5864788433e48cba2d5b423d7b9bc862f17d814 Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Wed, 14 Oct 2020 17:04:37 +0300 Subject: [PATCH 02/15] Add flag for http service --- cmd/root.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/root.go b/cmd/root.go index 45cdcb08c..86f24fded 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -122,6 +122,7 @@ func init() { viper.BindPFlag("ethereum.networkID", rootCmd.PersistentFlags().Lookup("eth-network-id")) viper.BindPFlag("ethereum.chainID", rootCmd.PersistentFlags().Lookup("eth-chain-id")) + viper.BindPFlag("http", rootCmd.PersistentFlags().Lookup("http")) viper.BindPFlag("http.addr", rootCmd.PersistentFlags().Lookup("http-addr")) viper.BindPFlag("http.port", rootCmd.PersistentFlags().Lookup("http-port")) From 03742bcfe2e0266993a39e0b10097a676e035315 Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Wed, 14 Oct 2020 17:06:01 +0300 Subject: [PATCH 03/15] Add web service for prometheus --- cmd/root.go | 7 +++++++ pkg/web/web.go | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 pkg/web/web.go diff --git a/cmd/root.go b/cmd/root.go index 86f24fded..d784a7a26 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -24,6 +24,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/vulcanize/ipld-eth-indexer/pkg/web" ) var ( @@ -62,6 +63,11 @@ func initFuncs(cmd *cobra.Command, args []string) { if err := logLevel(); err != nil { log.Fatal("Could not set log level: ", err) } + + if viper.GetBool("http") { + addr := fmt.Sprintf("%s:%s", viper.GetString("http.addr"), viper.GetString("http.port")) + web.Listen(addr) + } } func logLevel() error { @@ -101,6 +107,7 @@ func init() { rootCmd.PersistentFlags().String("eth-network-id", "1", "eth network id") rootCmd.PersistentFlags().String("eth-chain-id", "1", "eth chain id") + rootCmd.PersistentFlags().Bool("http", false, "enable http service") rootCmd.PersistentFlags().String("http-addr", "127.0.0.1", "http host") rootCmd.PersistentFlags().String("http-port", "8080", "http port") diff --git a/pkg/web/web.go b/pkg/web/web.go new file mode 100644 index 000000000..c13b04de2 --- /dev/null +++ b/pkg/web/web.go @@ -0,0 +1,24 @@ +package web + +import ( + "net/http" + + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" +) + +// Listen start listening http +func Listen(addr string) *http.Server { + mux := http.NewServeMux() + mux.Handle("/metrics", promhttp.Handler()) + srv := http.Server{ + Addr: addr, + Handler: mux, + } + go func() { + if err := srv.ListenAndServe(); err != nil { + logrus.Fatal(err) + } + }() + return &srv +} From 4410df5ec3edb0ad3500affb4da6a3b509677571 Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Wed, 14 Oct 2020 18:08:32 +0300 Subject: [PATCH 04/15] add prometheus to go.mod --- go.mod | 1 + go.sum | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/go.mod b/go.mod index 2affb37d0..118167b6a 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/multiformats/go-multihash v0.0.13 github.com/onsi/ginkgo v1.12.1 github.com/onsi/gomega v1.10.1 + github.com/prometheus/client_golang v1.5.1 github.com/sirupsen/logrus v1.6.0 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.7.0 diff --git a/go.sum b/go.sum index a7b41e564..ffc26c0d3 100644 --- a/go.sum +++ b/go.sum @@ -63,6 +63,7 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= @@ -685,6 +686,7 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0= github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= @@ -808,21 +810,25 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= From fdbcb9603f71af814d7d62a254c4ebee7545935d Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Wed, 14 Oct 2020 19:23:46 +0300 Subject: [PATCH 05/15] init metrics settings --- cmd/root.go | 5 +++++ pkg/prom/prom.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 pkg/prom/prom.go diff --git a/cmd/root.go b/cmd/root.go index d784a7a26..57583738e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -24,6 +24,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/vulcanize/ipld-eth-indexer/pkg/prom" "github.com/vulcanize/ipld-eth-indexer/pkg/web" ) @@ -68,6 +69,10 @@ func initFuncs(cmd *cobra.Command, args []string) { addr := fmt.Sprintf("%s:%s", viper.GetString("http.addr"), viper.GetString("http.port")) web.Listen(addr) } + + if viper.GetBool("metrics") { + prom.Init() + } } func logLevel() error { diff --git a/pkg/prom/prom.go b/pkg/prom/prom.go new file mode 100644 index 000000000..1b68b0725 --- /dev/null +++ b/pkg/prom/prom.go @@ -0,0 +1,56 @@ +package prom + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +// Env variables +const ( + METRICS = "METRICS" +) + +var ( + metrics bool + receipts prometheus.Counter + transactions prometheus.Counter + blocks prometheus.Counter +) + +// Init module initialization +func Init() { + metrics = true + blocks = promauto.NewCounter(prometheus.CounterOpts{ + Name: "blocks", + Help: "The total number of processed blocks", + }) + transactions = promauto.NewCounter(prometheus.CounterOpts{ + Name: "transactions", + Help: "The total number of processed transactions", + }) + receipts = promauto.NewCounter(prometheus.CounterOpts{ + Name: "receipts", + Help: "The total number of processed receipts", + }) +} + +// BlockInc block counter increment +func BlockInc() { + if metrics { + blocks.Inc() + } +} + +// TransactionInc transaction counter increment +func TransactionInc() { + if metrics { + transactions.Inc() + } +} + +// ReceiptInc receipt counter increment +func ReceiptInc() { + if metrics { + receipts.Inc() + } +} From b881dcca901469a67cea739b1a90edb1f8695b16 Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Wed, 14 Oct 2020 19:24:22 +0300 Subject: [PATCH 06/15] add metrics into indexer --- pkg/eth/indexer.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/eth/indexer.go b/pkg/eth/indexer.go index c8ab1e7d0..952f6634a 100644 --- a/pkg/eth/indexer.go +++ b/pkg/eth/indexer.go @@ -22,6 +22,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/vulcanize/ipld-eth-indexer/pkg/postgres" + "github.com/vulcanize/ipld-eth-indexer/pkg/prom" "github.com/vulcanize/ipld-eth-indexer/pkg/shared" ) @@ -94,6 +95,9 @@ func (in *CIDIndexer) indexHeaderCID(tx *sqlx.Tx, header HeaderModel) (int64, er RETURNING id`, header.BlockNumber, header.BlockHash, header.ParentHash, header.CID, header.TotalDifficulty, in.db.NodeID, header.Reward, header.StateRoot, header.TxRoot, header.RctRoot, header.UncleRoot, header.Bloom, header.Timestamp, header.MhKey, 1).Scan(&headerID) + if err == nil { + prom.BlockInc() + } return headerID, err } @@ -114,6 +118,7 @@ func (in *CIDIndexer) indexTransactionAndReceiptCIDs(tx *sqlx.Tx, payload CIDPay if err != nil { return err } + prom.TransactionInc() receiptCidMeta, ok := payload.ReceiptCIDs[common.HexToHash(trxCidMeta.TxHash)] if ok { if err := in.indexReceiptCID(tx, receiptCidMeta, txID); err != nil { @@ -130,6 +135,9 @@ func (in *CIDIndexer) indexTransactionCID(tx *sqlx.Tx, transaction TxModel, head ON CONFLICT (header_id, tx_hash) DO UPDATE SET (cid, dst, src, index, mh_key, tx_data, deployment) = ($3, $4, $5, $6, $7, $8, $9) RETURNING id`, headerID, transaction.TxHash, transaction.CID, transaction.Dst, transaction.Src, transaction.Index, transaction.MhKey, transaction.Data, transaction.Deployment).Scan(&txID) + if err == nil { + prom.TransactionInc() + } return txID, err } @@ -137,6 +145,9 @@ func (in *CIDIndexer) indexReceiptCID(tx *sqlx.Tx, rct ReceiptModel, txID int64) _, err := tx.Exec(`INSERT INTO eth.receipt_cids (tx_id, cid, contract, contract_hash, topic0s, topic1s, topic2s, topic3s, log_contracts, mh_key) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (tx_id) DO UPDATE SET (cid, contract, contract_hash, topic0s, topic1s, topic2s, topic3s, log_contracts, mh_key) = ($2, $3, $4, $5, $6, $7, $8, $9, $10)`, txID, rct.CID, rct.Contract, rct.ContractHash, rct.Topic0s, rct.Topic1s, rct.Topic2s, rct.Topic3s, rct.LogContracts, rct.MhKey) + if err == nil { + prom.ReceiptInc() + } return err } From 1700066d7654b7b0e936522231dba1528cd274c4 Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Thu, 15 Oct 2020 16:50:49 +0300 Subject: [PATCH 07/15] add DBStatsCollector --- pkg/postgres/postgres.go | 2 + pkg/prom/db_stats_collector.go | 146 +++++++++++++++++++++++++++++++++ pkg/prom/prom.go | 13 +-- 3 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 pkg/prom/db_stats_collector.go diff --git a/pkg/postgres/postgres.go b/pkg/postgres/postgres.go index dea76e19d..63e9c7a37 100644 --- a/pkg/postgres/postgres.go +++ b/pkg/postgres/postgres.go @@ -22,6 +22,7 @@ import ( "github.com/jmoiron/sqlx" _ "github.com/lib/pq" //postgres driver "github.com/vulcanize/ipld-eth-indexer/pkg/node" + "github.com/vulcanize/ipld-eth-indexer/pkg/prom" ) type DB struct { @@ -36,6 +37,7 @@ func NewDB(databaseConfig Config, node node.Info) (*DB, error) { if connectErr != nil { return &DB{}, ErrDBConnectionFailed(connectErr) } + prom.RegisterDBCollector(databaseConfig.Name, db) if databaseConfig.MaxOpen > 0 { db.SetMaxOpenConns(databaseConfig.MaxOpen) } diff --git a/pkg/prom/db_stats_collector.go b/pkg/prom/db_stats_collector.go new file mode 100644 index 000000000..b01c21045 --- /dev/null +++ b/pkg/prom/db_stats_collector.go @@ -0,0 +1,146 @@ +package prom + +import ( + "database/sql" + + "github.com/prometheus/client_golang/prometheus" +) + +const ( + namespace = "go_sqlx_stats" + subsystem = "connections" +) + +// DBStatsGetter is an interface that gets sql.DBStats. +type DBStatsGetter interface { + Stats() sql.DBStats +} + +// DBStatsCollector implements the prometheus.Collector interface. +type DBStatsCollector struct { + sg DBStatsGetter + + // descriptions of exported metrics + maxOpenDesc *prometheus.Desc + openDesc *prometheus.Desc + inUseDesc *prometheus.Desc + idleDesc *prometheus.Desc + waitedForDesc *prometheus.Desc + blockedSecondsDesc *prometheus.Desc + closedMaxIdleDesc *prometheus.Desc + closedMaxLifetimeDesc *prometheus.Desc +} + +// NewDBStatsCollector creates a new DBStatsCollector. +func NewDBStatsCollector(dbName string, sg DBStatsGetter) *DBStatsCollector { + labels := prometheus.Labels{"db_name": dbName} + return &DBStatsCollector{ + sg: sg, + maxOpenDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "max_open"), + "Maximum number of open connections to the database.", + nil, + labels, + ), + openDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "open"), + "The number of established connections both in use and idle.", + nil, + labels, + ), + inUseDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "in_use"), + "The number of connections currently in use.", + nil, + labels, + ), + idleDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "idle"), + "The number of idle connections.", + nil, + labels, + ), + waitedForDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "waited_for"), + "The total number of connections waited for.", + nil, + labels, + ), + blockedSecondsDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "blocked_seconds"), + "The total time blocked waiting for a new connection.", + nil, + labels, + ), + closedMaxIdleDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "closed_max_idle"), + "The total number of connections closed due to SetMaxIdleConns.", + nil, + labels, + ), + closedMaxLifetimeDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "closed_max_lifetime"), + "The total number of connections closed due to SetConnMaxLifetime.", + nil, + labels, + ), + } +} + +// Describe implements the prometheus.Collector interface. +func (c DBStatsCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- c.maxOpenDesc + ch <- c.openDesc + ch <- c.inUseDesc + ch <- c.idleDesc + ch <- c.waitedForDesc + ch <- c.blockedSecondsDesc + ch <- c.closedMaxIdleDesc + ch <- c.closedMaxLifetimeDesc +} + +// Collect implements the prometheus.Collector interface. +func (c DBStatsCollector) Collect(ch chan<- prometheus.Metric) { + stats := c.sg.Stats() + + ch <- prometheus.MustNewConstMetric( + c.maxOpenDesc, + prometheus.GaugeValue, + float64(stats.MaxOpenConnections), + ) + ch <- prometheus.MustNewConstMetric( + c.openDesc, + prometheus.GaugeValue, + float64(stats.OpenConnections), + ) + ch <- prometheus.MustNewConstMetric( + c.inUseDesc, + prometheus.GaugeValue, + float64(stats.InUse), + ) + ch <- prometheus.MustNewConstMetric( + c.idleDesc, + prometheus.GaugeValue, + float64(stats.Idle), + ) + ch <- prometheus.MustNewConstMetric( + c.waitedForDesc, + prometheus.CounterValue, + float64(stats.WaitCount), + ) + ch <- prometheus.MustNewConstMetric( + c.blockedSecondsDesc, + prometheus.CounterValue, + stats.WaitDuration.Seconds(), + ) + ch <- prometheus.MustNewConstMetric( + c.closedMaxIdleDesc, + prometheus.CounterValue, + float64(stats.MaxIdleClosed), + ) + ch <- prometheus.MustNewConstMetric( + c.closedMaxLifetimeDesc, + prometheus.CounterValue, + float64(stats.MaxLifetimeClosed), + ) +} diff --git a/pkg/prom/prom.go b/pkg/prom/prom.go index 1b68b0725..ebd236538 100644 --- a/pkg/prom/prom.go +++ b/pkg/prom/prom.go @@ -1,15 +1,11 @@ package prom import ( + "github.com/jmoiron/sqlx" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) -// Env variables -const ( - METRICS = "METRICS" -) - var ( metrics bool receipts prometheus.Counter @@ -34,6 +30,13 @@ func Init() { }) } +// RegisterDBCollector create metric colletor for given connection +func RegisterDBCollector(name string, db *sqlx.DB) { + if metrics { + prometheus.Register(NewDBStatsCollector(name, db)) + } +} + // BlockInc block counter increment func BlockInc() { if metrics { From 8e1cad1941c2f3904c7c3098ef43b2471f00a48b Mon Sep 17 00:00:00 2001 From: ramil Date: Fri, 16 Oct 2020 13:44:24 +0300 Subject: [PATCH 08/15] change prom namespace to ipld_eth_indexer --- pkg/prom/db_stats_collector.go | 2 +- pkg/prom/prom.go | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/prom/db_stats_collector.go b/pkg/prom/db_stats_collector.go index b01c21045..3bab65730 100644 --- a/pkg/prom/db_stats_collector.go +++ b/pkg/prom/db_stats_collector.go @@ -7,7 +7,7 @@ import ( ) const ( - namespace = "go_sqlx_stats" + namespace = "ipld_eth_indexer" subsystem = "connections" ) diff --git a/pkg/prom/prom.go b/pkg/prom/prom.go index ebd236538..dbdbb739a 100644 --- a/pkg/prom/prom.go +++ b/pkg/prom/prom.go @@ -17,16 +17,19 @@ var ( func Init() { metrics = true blocks = promauto.NewCounter(prometheus.CounterOpts{ - Name: "blocks", - Help: "The total number of processed blocks", + Namespace: namespace, + Name: "blocks", + Help: "The total number of processed blocks", }) transactions = promauto.NewCounter(prometheus.CounterOpts{ - Name: "transactions", - Help: "The total number of processed transactions", + Namespace: namespace, + Name: "transactions", + Help: "The total number of processed transactions", }) receipts = promauto.NewCounter(prometheus.CounterOpts{ - Name: "receipts", - Help: "The total number of processed receipts", + Namespace: namespace, + Name: "receipts", + Help: "The total number of processed receipts", }) } From 54c8a9dc7eae2ccb214bcedff692cb04992a3e5b Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Fri, 16 Oct 2020 15:08:12 +0300 Subject: [PATCH 09/15] add observation of time metric --- pkg/eth/transformer.go | 29 +++++++++++---- pkg/prom/prom.go | 83 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/pkg/eth/transformer.go b/pkg/eth/transformer.go index 5331d4f04..18c6855ca 100644 --- a/pkg/eth/transformer.go +++ b/pkg/eth/transformer.go @@ -35,6 +35,7 @@ import ( "github.com/vulcanize/ipld-eth-indexer/pkg/ipfs/ipld" "github.com/vulcanize/ipld-eth-indexer/pkg/postgres" + "github.com/vulcanize/ipld-eth-indexer/pkg/prom" "github.com/vulcanize/ipld-eth-indexer/pkg/shared" ) @@ -95,7 +96,9 @@ func (sdt *StateDiffTransformer) Transform(workerID int, payload statediff.Paylo } // Calculate reward reward := CalcEthBlockReward(block.Header(), block.Uncles(), block.Transactions(), receipts) - traceMsg += fmt.Sprintf("payload decoding time: %s\r\n", time.Now().Sub(t).String()) + tDiff := time.Now().Sub(t) + prom.SetTimeMetric("t_payload_decode", tDiff) + traceMsg += fmt.Sprintf("payload decoding time: %s\r\n", tDiff.String()) t = time.Now() // Begin new db tx for everything tx, err := sdt.indexer.db.Beginx() @@ -111,12 +114,16 @@ func (sdt *StateDiffTransformer) Transform(workerID int, payload statediff.Paylo shared.Rollback(tx) } else { err = tx.Commit() - traceMsg += fmt.Sprintf("postgres transaction commit duration: %s\r\n", time.Now().Sub(t).String()) + tDiff := time.Now().Sub(t) + prom.SetTimeMetric("t_postgres_commit", tDiff) + traceMsg += fmt.Sprintf("postgres transaction commit duration: %s\r\n", tDiff.String()) } traceMsg += fmt.Sprintf(" TOTAL PROCESSING TIME: %s\r\n", time.Now().Sub(start).String()) logrus.Info(traceMsg) }() - traceMsg += fmt.Sprintf("time spent waiting for free postgres tx: %s:\r\n", time.Now().Sub(t).String()) + tDiff = time.Now().Sub(t) + prom.SetTimeMetric("t_free_postgres", tDiff) + traceMsg += fmt.Sprintf("time spent waiting for free postgres tx: %s:\r\n", tDiff.String()) t = time.Now() // Publish and index header, collect headerID @@ -124,13 +131,17 @@ func (sdt *StateDiffTransformer) Transform(workerID int, payload statediff.Paylo if err != nil { return 0, err } - traceMsg += fmt.Sprintf("header processing time: %s\r\n", time.Now().Sub(t).String()) + tDiff = time.Now().Sub(t) + prom.SetTimeMetric("t_header_rocessing", tDiff) + traceMsg += fmt.Sprintf("header processing time: %s\r\n", tDiff.String()) t = time.Now() // Publish and index uncles if err := sdt.processUncles(tx, headerID, height, uncleNodes); err != nil { return 0, err } - traceMsg += fmt.Sprintf("uncle processing time: %s\r\n", time.Now().Sub(t).String()) + tDiff = time.Now().Sub(t) + prom.SetTimeMetric("t_uncle_processing", tDiff) + traceMsg += fmt.Sprintf("uncle processing time: %s\r\n", tDiff.String()) t = time.Now() // Publish and index receipts and txs if err := sdt.processReceiptsAndTxs(tx, processArgs{ @@ -145,13 +156,17 @@ func (sdt *StateDiffTransformer) Transform(workerID int, payload statediff.Paylo }); err != nil { return 0, err } - traceMsg += fmt.Sprintf("tx and receipt processing time: %s\r\n", time.Now().Sub(t).String()) + tDiff = time.Now().Sub(t) + prom.SetTimeMetric("t_tx_receipt_processing", tDiff) + traceMsg += fmt.Sprintf("tx and receipt processing time: %s\r\n", tDiff.String()) t = time.Now() // Publish and index state and storage nodes if err := sdt.processStateAndStorage(tx, headerID, stateDiff); err != nil { return 0, err } - traceMsg += fmt.Sprintf("state and storage processing time: %s\r\n", time.Now().Sub(t).String()) + tDiff = time.Now().Sub(t) + prom.SetTimeMetric("t_state_store_processing", tDiff) + traceMsg += fmt.Sprintf("state and storage processing time: %s\r\n", tDiff.String()) t = time.Now() return height, err // return error explicity so that the defer() assigns to it } diff --git a/pkg/prom/prom.go b/pkg/prom/prom.go index dbdbb739a..76707d252 100644 --- a/pkg/prom/prom.go +++ b/pkg/prom/prom.go @@ -1,21 +1,35 @@ package prom import ( + "time" + "github.com/jmoiron/sqlx" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) +const statsSubsystem = "stats" + var ( - metrics bool + metrics bool + receipts prometheus.Counter transactions prometheus.Counter blocks prometheus.Counter + + tPayloadDecode prometheus.Histogram // payload decoding time: 58.173µs + tFreePostgres prometheus.Histogram // time spent waiting for free postgres tx: 94.511µs + tPostgresCommit prometheus.Histogram // postgres transaction commit duration: 1.509643ms + tHeaderProcessing prometheus.Histogram // header processing time: 1.057721ms + tUncleProcessing prometheus.Histogram // uncle processing time: 140ns + tTxAndRecProcessing prometheus.Histogram // tx and receipt processing time: 1.749µs + tStateAndStoreProcessing prometheus.Histogram // state and storage processing time: 4.737994ms ) // Init module initialization func Init() { metrics = true + blocks = promauto.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Name: "blocks", @@ -31,6 +45,49 @@ func Init() { Name: "receipts", Help: "The total number of processed receipts", }) + + tPayloadDecode = promauto.NewHistogram(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: statsSubsystem, + Name: "t_payload_decode", + Help: "Payload decoding time", + }) + tFreePostgres = promauto.NewHistogram(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: statsSubsystem, + Name: "t_free_postgres", + Help: "Time spent waiting for free postgres tx", + }) + tPostgresCommit = promauto.NewHistogram(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: statsSubsystem, + Name: "t_postgres_commit", + Help: "Postgres transaction commit duration", + }) + tHeaderProcessing = promauto.NewHistogram(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: statsSubsystem, + Name: "t_header_rocessing", + Help: "Header processing time", + }) + tUncleProcessing = promauto.NewHistogram(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: statsSubsystem, + Name: "t_uncle_processing", + Help: "Uncle processing time", + }) + tTxAndRecProcessing = promauto.NewHistogram(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: statsSubsystem, + Name: "t_tx_receipt_processing", + Help: "Tx and receipt processing time", + }) + tStateAndStoreProcessing = promauto.NewHistogram(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: statsSubsystem, + Name: "t_state_store_processing", + Help: "State and storage processing time", + }) } // RegisterDBCollector create metric colletor for given connection @@ -60,3 +117,27 @@ func ReceiptInc() { receipts.Inc() } } + +// SetTimeMetric time metric observation +func SetTimeMetric(name string, t time.Duration) { + if !metrics { + return + } + tAsF64 := float64(t.Microseconds()) + switch name { + case "t_payload_decode": + tPayloadDecode.Observe(tAsF64) + case "t_free_postgres": + tFreePostgres.Observe(tAsF64) + case "t_postgres_commit": + tPostgresCommit.Observe(tAsF64) + case "t_header_rocessing": + tHeaderProcessing.Observe(tAsF64) + case "t_uncle_processing": + tUncleProcessing.Observe(tAsF64) + case "t_tx_receipt_processing": + tTxAndRecProcessing.Observe(tAsF64) + case "t_state_store_processing": + tStateAndStoreProcessing.Observe(tAsF64) + } +} From 72adabf95fe90303e49b7b137378fb23a9ce26bb Mon Sep 17 00:00:00 2001 From: ramil Date: Fri, 16 Oct 2020 16:06:29 +0300 Subject: [PATCH 10/15] prometheus metrics: use seconds --- pkg/eth/transformer.go | 2 +- pkg/prom/prom.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/eth/transformer.go b/pkg/eth/transformer.go index 18c6855ca..842dc5c03 100644 --- a/pkg/eth/transformer.go +++ b/pkg/eth/transformer.go @@ -132,7 +132,7 @@ func (sdt *StateDiffTransformer) Transform(workerID int, payload statediff.Paylo return 0, err } tDiff = time.Now().Sub(t) - prom.SetTimeMetric("t_header_rocessing", tDiff) + prom.SetTimeMetric("t_header_processing", tDiff) traceMsg += fmt.Sprintf("header processing time: %s\r\n", tDiff.String()) t = time.Now() // Publish and index uncles diff --git a/pkg/prom/prom.go b/pkg/prom/prom.go index 76707d252..f62d33633 100644 --- a/pkg/prom/prom.go +++ b/pkg/prom/prom.go @@ -67,7 +67,7 @@ func Init() { tHeaderProcessing = promauto.NewHistogram(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: statsSubsystem, - Name: "t_header_rocessing", + Name: "t_header_processing", Help: "Header processing time", }) tUncleProcessing = promauto.NewHistogram(prometheus.HistogramOpts{ @@ -123,7 +123,7 @@ func SetTimeMetric(name string, t time.Duration) { if !metrics { return } - tAsF64 := float64(t.Microseconds()) + tAsF64 := t.Seconds() switch name { case "t_payload_decode": tPayloadDecode.Observe(tAsF64) @@ -131,7 +131,7 @@ func SetTimeMetric(name string, t time.Duration) { tFreePostgres.Observe(tAsF64) case "t_postgres_commit": tPostgresCommit.Observe(tAsF64) - case "t_header_rocessing": + case "t_header_processing": tHeaderProcessing.Observe(tAsF64) case "t_uncle_processing": tUncleProcessing.Observe(tAsF64) From b642a9cf8371cb2f36742cd1107dab0e81398861 Mon Sep 17 00:00:00 2001 From: ramil Date: Fri, 16 Oct 2020 16:22:00 +0300 Subject: [PATCH 11/15] prometheus config and grafana dashboard --- monitoring/grafana/dashboard_main.json | 822 +++++++++++++++++++++++++ monitoring/prometheus.yml | 7 + 2 files changed, 829 insertions(+) create mode 100644 monitoring/grafana/dashboard_main.json create mode 100644 monitoring/prometheus.yml diff --git a/monitoring/grafana/dashboard_main.json b/monitoring/grafana/dashboard_main.json new file mode 100644 index 000000000..cb4385aa7 --- /dev/null +++ b/monitoring/grafana/dashboard_main.json @@ -0,0 +1,822 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 2, + "iteration": 1602852966068, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_blocks[1m])", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Blocks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_receipts[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Receipts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_transactions[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Transactions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "unit": "s" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_stats_t_postgres_commit_sum[1m])/rate(ipld_eth_indexer_stats_t_postgres_commit_count[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Postgres transaction commit duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "", + "fieldConfig": { + "defaults": { + "custom": {}, + "unit": "s" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 19 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_stats_t_payload_decode_sum[1m])/rate(ipld_eth_indexer_stats_t_payload_decode_count[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Payload decoding time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "", + "fieldConfig": { + "defaults": { + "custom": {}, + "unit": "s" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 19 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_stats_t_free_postgres_sum[1m])/rate(ipld_eth_indexer_stats_t_free_postgres_count[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Time spent waiting for free postgres", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "unit": "s" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 29 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_stats_t_header_processing_sum[1m])/rate(ipld_eth_indexer_stats_t_header_processing_count[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Header processing time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "unit": "s" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 29 + }, + "hiddenSeries": false, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_stats_t_uncle_processing_sum[1m])/rate(ipld_eth_indexer_stats_t_uncle_processing_count[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Uncle processing time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "ipld-eth-indexer", + "uid": "LU0rKucGz", + "version": 24 +} diff --git a/monitoring/prometheus.yml b/monitoring/prometheus.yml new file mode 100644 index 000000000..d8bc4037d --- /dev/null +++ b/monitoring/prometheus.yml @@ -0,0 +1,7 @@ +global: + scrape_interval: 10s + +scrape_configs: + - job_name: 'ipld-eth-indexer' + static_configs: + - targets: ['localhost:8080'] From b2eeee1a06b2e1880f477ed6a783a69be227a258 Mon Sep 17 00:00:00 2001 From: ramil Date: Fri, 16 Oct 2020 16:33:57 +0300 Subject: [PATCH 12/15] monito --- README.md | 9 +++++++++ monitoring/grafana.png | Bin 0 -> 127285 bytes 2 files changed, 9 insertions(+) create mode 100644 monitoring/grafana.png diff --git a/README.md b/README.md index 69ea070c9..1cf7ccef3 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,15 @@ of Postgres can be found [here](./documentation/ipfs.md) `make test` will run the unit tests `make test` setups a clean `vulcanize_testing` db +## Monitoring + +* Enable http server and metrics using parameters `--http --metrics` +* ipld-eth-indexer exposes prometheus metrics at `/metric` endpoint +* start prometheus using `monitoring/prometheus.yml` config (`prometheus --config.file=monitoring/prometheus.yml`) +* start grafana, connect to prometheus datasource and import dashboard from `monitoring/grafana/dashboard_main.json` + +![](monitoring/grafana.png) + ## Contributing Contributions are welcome! diff --git a/monitoring/grafana.png b/monitoring/grafana.png new file mode 100644 index 0000000000000000000000000000000000000000..3ee64b54d202723d051ac68807b5f02e0fe24d66 GIT binary patch literal 127285 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 S7F;)gf6qlEg|h|KUH=zp%1U1V literal 0 HcmV?d00001 From 116885da933814b482b3459c2ab4869eb0b569d2 Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Fri, 16 Oct 2020 18:33:38 +0300 Subject: [PATCH 13/15] add metric for PayloadChan --- pkg/prom/prom.go | 29 ++++++++++++++++++++++------- pkg/sync/service.go | 2 ++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/pkg/prom/prom.go b/pkg/prom/prom.go index f62d33633..a93a4d438 100644 --- a/pkg/prom/prom.go +++ b/pkg/prom/prom.go @@ -17,13 +17,15 @@ var ( transactions prometheus.Counter blocks prometheus.Counter - tPayloadDecode prometheus.Histogram // payload decoding time: 58.173µs - tFreePostgres prometheus.Histogram // time spent waiting for free postgres tx: 94.511µs - tPostgresCommit prometheus.Histogram // postgres transaction commit duration: 1.509643ms - tHeaderProcessing prometheus.Histogram // header processing time: 1.057721ms - tUncleProcessing prometheus.Histogram // uncle processing time: 140ns - tTxAndRecProcessing prometheus.Histogram // tx and receipt processing time: 1.749µs - tStateAndStoreProcessing prometheus.Histogram // state and storage processing time: 4.737994ms + lenPayloadChan prometheus.Gauge + + tPayloadDecode prometheus.Histogram + tFreePostgres prometheus.Histogram + tPostgresCommit prometheus.Histogram + tHeaderProcessing prometheus.Histogram + tUncleProcessing prometheus.Histogram + tTxAndRecProcessing prometheus.Histogram + tStateAndStoreProcessing prometheus.Histogram ) // Init module initialization @@ -46,6 +48,12 @@ func Init() { Help: "The total number of processed receipts", }) + lenPayloadChan = promauto.NewGauge(prometheus.GaugeOpts{ + Namespace: namespace, + Name: "len_payload_chan", + Help: "Current length of publishPayload", + }) + tPayloadDecode = promauto.NewHistogram(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: statsSubsystem, @@ -118,6 +126,13 @@ func ReceiptInc() { } } +// SetLenPayloadChan set chan length +func SetLenPayloadChan(ln int) { + if metrics { + lenPayloadChan.Set(float64(ln)) + } +} + // SetTimeMetric time metric observation func SetTimeMetric(name string, t time.Duration) { if !metrics { diff --git a/pkg/sync/service.go b/pkg/sync/service.go index 1d52ade5f..8ea4bcc8d 100644 --- a/pkg/sync/service.go +++ b/pkg/sync/service.go @@ -27,6 +27,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/vulcanize/ipld-eth-indexer/pkg/eth" + "github.com/vulcanize/ipld-eth-indexer/pkg/prom" "github.com/vulcanize/ipld-eth-indexer/pkg/shared" ) @@ -113,6 +114,7 @@ func (sap *Service) Sync(wg *sync.WaitGroup) error { <-publishPayload publishPayload <- diffPayload } + prom.SetLenPayloadChan(len(publishPayload)) case err := <-sub.Err(): log.Errorf("ethereumm sync subscription error: %v", err) case <-sap.QuitChan: From 9ae62b6ab3eec5dbc1916a3f188db09a297324ec Mon Sep 17 00:00:00 2001 From: Ilnur Galiev Date: Fri, 16 Oct 2020 23:30:33 +0300 Subject: [PATCH 14/15] deascrese metric LenPayloadChan --- pkg/sync/service.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/sync/service.go b/pkg/sync/service.go index 8ea4bcc8d..8007bc28c 100644 --- a/pkg/sync/service.go +++ b/pkg/sync/service.go @@ -135,6 +135,7 @@ func (sap *Service) transform(wg *sync.WaitGroup, id int, statediffChan <-chan s for { select { case diff := <-statediffChan: + prom.SetLenPayloadChan(len(statediffChan)) blockNumber, err := sap.Transformer.Transform(id, diff) if err != nil { log.Errorf("ethereum sync worker %d transformer error: %v", id, err) From e7a58bdc50df53c2ccd842b5897f7a67d5cd1119 Mon Sep 17 00:00:00 2001 From: ramil Date: Mon, 19 Oct 2020 17:37:31 +0300 Subject: [PATCH 15/15] updated grafana dashboard --- monitoring/grafana/dashboard_main.json | 297 ++++++++++++++++++++++--- 1 file changed, 271 insertions(+), 26 deletions(-) diff --git a/monitoring/grafana/dashboard_main.json b/monitoring/grafana/dashboard_main.json index cb4385aa7..135d48d8c 100644 --- a/monitoring/grafana/dashboard_main.json +++ b/monitoring/grafana/dashboard_main.json @@ -16,9 +16,159 @@ "gnetId": null, "graphTooltip": 0, "id": 2, - "iteration": 1602852966068, "links": [], "panels": [ + { + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "max": 2000, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 400 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 18, + "options": { + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "7.2.1", + "targets": [ + { + "expr": "ipld_eth_indexer_len_payload_chan", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Payload Channel Length", + "type": "gauge" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_len_payload_chan[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Payload Channel growth", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, { "aliasColors": {}, "bars": false, @@ -52,7 +202,7 @@ "h": 9, "w": 12, "x": 0, - "y": 0 + "y": 9 }, "hiddenSeries": false, "id": 2, @@ -148,7 +298,7 @@ "h": 9, "w": 12, "x": 12, - "y": 0 + "y": 9 }, "hiddenSeries": false, "id": 4, @@ -243,10 +393,10 @@ "h": 10, "w": 12, "x": 0, - "y": 9 + "y": 18 }, "hiddenSeries": false, - "id": 6, + "id": 22, "legend": { "avg": false, "current": false, @@ -273,7 +423,7 @@ "steppedLine": false, "targets": [ { - "expr": "rate(ipld_eth_indexer_transactions[1m])", + "expr": "rate(ipld_eth_indexer_stats_t_postgres_commit_count[1m])", "interval": "", "legendFormat": "", "refId": "A" @@ -283,7 +433,7 @@ "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Transactions", + "title": "Pg Commits per second", "tooltip": { "shared": true, "sort": 0, @@ -339,7 +489,7 @@ "h": 10, "w": 12, "x": 12, - "y": 9 + "y": 18 }, "hiddenSeries": false, "id": 10, @@ -422,11 +572,9 @@ "dashLength": 10, "dashes": false, "datasource": null, - "description": "", "fieldConfig": { "defaults": { - "custom": {}, - "unit": "s" + "custom": {} }, "overrides": [] }, @@ -436,10 +584,10 @@ "h": 10, "w": 12, "x": 0, - "y": 19 + "y": 28 }, "hiddenSeries": false, - "id": 8, + "id": 6, "legend": { "avg": false, "current": false, @@ -466,7 +614,7 @@ "steppedLine": false, "targets": [ { - "expr": "rate(ipld_eth_indexer_stats_t_payload_decode_sum[1m])/rate(ipld_eth_indexer_stats_t_payload_decode_count[1m])", + "expr": "rate(ipld_eth_indexer_transactions[1m])", "interval": "", "legendFormat": "", "refId": "A" @@ -476,7 +624,7 @@ "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Payload decoding time", + "title": "Transactions", "tooltip": { "shared": true, "sort": 0, @@ -492,7 +640,7 @@ }, "yaxes": [ { - "format": "s", + "format": "short", "label": null, "logBase": 1, "max": null, @@ -533,7 +681,7 @@ "h": 10, "w": 12, "x": 12, - "y": 19 + "y": 28 }, "hiddenSeries": false, "id": 12, @@ -616,6 +764,7 @@ "dashLength": 10, "dashes": false, "datasource": null, + "description": "", "fieldConfig": { "defaults": { "custom": {}, @@ -626,13 +775,13 @@ "fill": 1, "fillGradient": 0, "gridPos": { - "h": 8, + "h": 10, "w": 12, "x": 0, - "y": 29 + "y": 38 }, "hiddenSeries": false, - "id": 14, + "id": 8, "legend": { "avg": false, "current": false, @@ -659,7 +808,7 @@ "steppedLine": false, "targets": [ { - "expr": "rate(ipld_eth_indexer_stats_t_header_processing_sum[1m])/rate(ipld_eth_indexer_stats_t_header_processing_count[1m])", + "expr": "rate(ipld_eth_indexer_stats_t_payload_decode_sum[1m])/rate(ipld_eth_indexer_stats_t_payload_decode_count[1m])", "interval": "", "legendFormat": "", "refId": "A" @@ -669,7 +818,7 @@ "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Header processing time", + "title": "Payload decoding time", "tooltip": { "shared": true, "sort": 0, @@ -725,7 +874,7 @@ "h": 8, "w": 12, "x": 12, - "y": 29 + "y": 38 }, "hiddenSeries": false, "id": 16, @@ -801,9 +950,105 @@ "align": false, "alignLevel": null } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "unit": "s" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 48 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(ipld_eth_indexer_stats_t_header_processing_sum[1m])/rate(ipld_eth_indexer_stats_t_header_processing_count[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Header processing time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } } ], - "refresh": "", + "refresh": "10s", "schemaVersion": 26, "style": "dark", "tags": [], @@ -818,5 +1063,5 @@ "timezone": "", "title": "ipld-eth-indexer", "uid": "LU0rKucGz", - "version": 24 -} + "version": 31 +} \ No newline at end of file