diff --git a/cmd/tendermint/commands/run_node.go b/cmd/tendermint/commands/run_node.go index 7773f8daa6..cafbed2ced 100644 --- a/cmd/tendermint/commands/run_node.go +++ b/cmd/tendermint/commands/run_node.go @@ -12,6 +12,7 @@ import ( cfg "github.com/tendermint/tendermint/config" tmos "github.com/tendermint/tendermint/libs/os" nm "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/pkg/trace" ) var ( @@ -93,6 +94,19 @@ func AddNodeFlags(cmd *cobra.Command) { "db_dir", config.DBPath, "database directory") + + cmd.PersistentFlags().String( + trace.FlagInfluxDBURL, + config.Instrumentation.InfluxURL, + trace.FlagInfluxDBURLDescription, + ) + + cmd.PersistentFlags().String( + trace.FlagInfluxDBToken, + config.Instrumentation.InfluxToken, + trace.FlagInfluxDBTokenDescription, + ) + } // NewRunNodeCmd returns the command that allows the CLI to start a node. diff --git a/config/config.go b/config/config.go index e6814588f2..706f89eb08 100644 --- a/config/config.go +++ b/config/config.go @@ -1158,6 +1158,21 @@ type InstrumentationConfig struct { // Instrumentation namespace. Namespace string `mapstructure:"namespace"` + + // InfluxURL is the influxdb url. + InfluxURL string `mapstructure:"influx_url"` + + // InfluxToken is the influxdb token. + InfluxToken string `mapstructure:"influx_token"` + + // InfluxOrg is the influxdb organization. + InfluxOrg string `mapstructure:"influx_org"` + + // InfluxBucket is the influxdb bucket. + InfluxBucket string `mapstructure:"influx_bucket"` + + // InfluxBatchSize is the number of points to write in a single batch. + InfluxBatchSize int `mapstructure:"influx_batch_size"` } // DefaultInstrumentationConfig returns a default configuration for metrics @@ -1168,6 +1183,10 @@ func DefaultInstrumentationConfig() *InstrumentationConfig { PrometheusListenAddr: ":26660", MaxOpenConnections: 3, Namespace: "tendermint", + InfluxURL: "", + InfluxOrg: "celestia", + InfluxBucket: "e2e", + InfluxBatchSize: 20, } } @@ -1183,6 +1202,23 @@ func (cfg *InstrumentationConfig) ValidateBasic() error { if cfg.MaxOpenConnections < 0 { return errors.New("max_open_connections can't be negative") } + // if there is not InfluxURL configured, then we do not need to validate the rest + // of the config because we are not connecting. + if cfg.InfluxURL == "" { + return nil + } + if cfg.InfluxToken == "" { + return fmt.Errorf("token is required") + } + if cfg.InfluxOrg == "" { + return fmt.Errorf("org is required") + } + if cfg.InfluxBucket == "" { + return fmt.Errorf("bucket is required") + } + if cfg.InfluxBatchSize <= 0 { + return fmt.Errorf("batch size must be greater than 0") + } return nil } diff --git a/config/toml.go b/config/toml.go index 6a2af7bbf3..d4897525e5 100644 --- a/config/toml.go +++ b/config/toml.go @@ -535,6 +535,22 @@ max_open_connections = {{ .Instrumentation.MaxOpenConnections }} # Instrumentation namespace namespace = "{{ .Instrumentation.Namespace }}" + +# The URL of the influxdb instance to use for remote event +# collection. If empty, remote event collection is disabled. +influx_url = "{{ .Instrumentation.InfluxURL }}" + +# The influxdb token to use for remote event collection. +influx_token = "{{ .Instrumentation.InfluxToken }}" + +# The influxdb bucket to use for remote event collection. +influx_bucket = "{{ .Instrumentation.InfluxBucket }}" + +# The influxdb org to use for event remote collection. +influx_org = "{{ .Instrumentation.InfluxOrg }}" + +# The size of the batches that are sent to the database. +influx_batch_size = {{ .Instrumentation.InfluxBatchSize }} ` /****** these are for test settings ***********/ diff --git a/consensus/state.go b/consensus/state.go index 81fa4fb572..6ea92d4a07 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -24,6 +24,7 @@ import ( "github.com/tendermint/tendermint/libs/service" tmsync "github.com/tendermint/tendermint/libs/sync" "github.com/tendermint/tendermint/p2p" + "github.com/tendermint/tendermint/pkg/trace" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" @@ -140,6 +141,8 @@ type State struct { // for reporting metrics metrics *Metrics + + eventCollector *trace.Client } // StateOption sets an optional parameter on the State. @@ -170,6 +173,7 @@ func NewState( evpool: evpool, evsw: tmevents.NewEventSwitch(), metrics: NopMetrics(), + eventCollector: &trace.Client{}, } // set function defaults (may be overwritten before calling Start) @@ -211,6 +215,11 @@ func StateMetrics(metrics *Metrics) StateOption { return func(cs *State) { cs.metrics = metrics } } +// SetEventCollector sets the remote event collector. +func SetEventCollector(ec *trace.Client) StateOption { + return func(cs *State) { cs.eventCollector = ec } +} + // String returns a string. func (cs *State) String() string { // better not to access shared variables diff --git a/go.mod b/go.mod index d02b9e2f4f..9aed8c5cf1 100644 --- a/go.mod +++ b/go.mod @@ -54,6 +54,8 @@ require ( google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 ) +require github.com/influxdata/influxdb-client-go/v2 v2.12.2 + require ( 4d63.com/gochecknoglobals v0.1.0 // indirect github.com/Abirdcfly/dupword v0.0.7 // indirect @@ -90,10 +92,10 @@ require ( github.com/containerd/typeurl v1.0.2 // indirect github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/creachadair/taskgroup v0.3.2 github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/daixiang0/gci v0.8.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/denis-tingaikin/go-header v0.4.3 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect @@ -150,6 +152,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a // indirect github.com/jgautheron/goconst v1.5.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect @@ -203,7 +206,6 @@ require ( github.com/polyfloyd/go-errorlint v1.0.5 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.8.0 // indirect github.com/quasilyte/go-ruleguard v0.3.18 // indirect github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f // indirect github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect @@ -272,3 +274,8 @@ require ( mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 // indirect ) + +require ( + github.com/creachadair/taskgroup v0.3.2 + github.com/prometheus/procfs v0.8.0 // indirect +) diff --git a/go.sum b/go.sum index ead7f2d167..051b13cbe3 100644 --- a/go.sum +++ b/go.sum @@ -251,6 +251,7 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ github.com/cristalhq/acmd v0.8.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/daixiang0/gci v0.8.1 h1:T4xpSC+hmsi4CSyuYfIJdMZAr9o7xZmHpQVygMghGZ4= @@ -260,6 +261,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= +github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA= @@ -331,7 +334,9 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-critic/go-critic v0.6.5 h1:fDaR/5GWURljXwF8Eh31T2GZNz9X4jeboS912mWF8Uo= @@ -358,6 +363,8 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -450,6 +457,7 @@ github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzr github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs= github.com/golangci/golangci-lint v1.50.1 h1:C829clMcZXEORakZlwpk7M4iDw2XiwxxKaG504SZ9zY= github.com/golangci/golangci-lint v1.50.1/go.mod h1:AQjHBopYS//oB8xs0y0M/dtxdKHkdhl0RvmjUct0/4w= +github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= @@ -512,6 +520,7 @@ github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1: github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -603,8 +612,12 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb-client-go/v2 v2.12.2 h1:uYABKdrEKlYm+++qfKdbgaHKBPmoWR5wpbmj6MBB/2g= +github.com/influxdata/influxdb-client-go/v2 v2.12.2/go.mod h1:YteV91FiQxRdccyJ2cHvj2f/5sq4y4Njqu1fQzsQCOU= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/informalsystems/tm-load-test v1.0.0 h1:e1IeUw8701HWCMuOM1vLM/XcpH2Lrb88GNWdFAPDmmA= github.com/informalsystems/tm-load-test v1.0.0/go.mod h1:WVaSKaQdfZK3v0C74EMzn7//+3aeCZF8wkIKBz2/M74= github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a h1:d4+I1YEKVmWZrgkt6jpXBnLgV2ZjO0YxEtLDdfIZfH4= @@ -675,6 +688,8 @@ github.com/kunwardeep/paralleltest v1.0.6 h1:FCKYMF1OF2+RveWlABsdnmsvJrei5aoyZoa github.com/kunwardeep/paralleltest v1.0.6/go.mod h1:Y0Y0XISdZM5IKm3TREQMZ6iteqn1YuwCsJO/0kL9Zes= github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= github.com/ldez/tagliatelle v0.3.1 h1:3BqVVlReVUZwafJUwQ+oxbx2BEX2vUG4Yu/NOfMiKiM= @@ -698,6 +713,8 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= github.com/maratori/testpackage v1.1.0 h1:GJY4wlzQhuBusMF1oahQCBtUV/AQ/k69IZ68vxaac2Q= @@ -706,9 +723,12 @@ github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7 github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -717,6 +737,7 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -1116,6 +1137,9 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/uudashr/gocognit v1.0.6 h1:2Cgi6MweCsdB6kpcVQp7EW4U23iBFQWfTXiWlyp842Y= github.com/uudashr/gocognit v1.0.6/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vektra/mockery/v2 v2.14.0 h1:KZ1p5Hrn8tiY+LErRMr14HHle6khxo+JKOXLBW/yfqs= github.com/vektra/mockery/v2 v2.14.0/go.mod h1:bnD1T8tExSgPD1ripLkDbr60JA9VtQeu12P3wgLZd7M= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -1205,7 +1229,9 @@ golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -1371,6 +1397,7 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1404,6 +1431,7 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1471,6 +1499,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/node/node.go b/node/node.go index 3d4d7ac107..0740cf0bed 100644 --- a/node/node.go +++ b/node/node.go @@ -23,6 +23,7 @@ import ( cs "github.com/tendermint/tendermint/consensus" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/evidence" + "github.com/tendermint/tendermint/pkg/trace" tmjson "github.com/tendermint/tendermint/libs/json" "github.com/tendermint/tendermint/libs/log" @@ -231,6 +232,7 @@ type Node struct { blockIndexer indexer.BlockIndexer indexerService *txindex.IndexerService prometheusSrv *http.Server + influxDBClient *trace.Client } func initDBs(config *cfg.Config, dbProvider DBProvider) (blockStore *store.BlockStore, stateDB dbm.DB, err error) { @@ -506,6 +508,7 @@ func createConsensusReactor(config *cfg.Config, waitSync bool, eventBus *types.EventBus, consensusLogger log.Logger, + evCollector *trace.Client, ) (*cs.Reactor, *cs.State) { consensusState := cs.NewState( config.Consensus, @@ -515,6 +518,7 @@ func createConsensusReactor(config *cfg.Config, mempool, evidencePool, cs.StateMetrics(csMetrics), + cs.SetEventCollector(evCollector), ) consensusState.SetLogger(consensusLogger) if privValidator != nil { @@ -832,6 +836,19 @@ func NewNode(config *cfg.Config, csMetrics, p2pMetrics, memplMetrics, smMetrics := metricsProvider(genDoc.ChainID) + // create an optional influxdb client to send arbitary data to a remote + // influxdb server. This is used to collect trace data from many different nodes + // in a network. + influxdbClient, err := trace.NewClient( + config.Instrumentation, + logger, + genDoc.ChainID, + string(nodeKey.ID()), + ) + if err != nil { + return nil, err + } + // Make MempoolReactor mempool, mempoolReactor := createMempoolAndMempoolReactor(config, proxyApp, state, memplMetrics, logger) @@ -866,7 +883,7 @@ func NewNode(config *cfg.Config, } consensusReactor, consensusState := createConsensusReactor( config, state, blockExec, blockStore, mempool, evidencePool, - privValidator, csMetrics, stateSync || fastSync, eventBus, consensusLogger, + privValidator, csMetrics, stateSync || fastSync, eventBus, consensusLogger, influxdbClient, ) // Set up state sync reactor, and schedule a sync if requested. @@ -964,6 +981,7 @@ func NewNode(config *cfg.Config, indexerService: indexerService, blockIndexer: blockIndexer, eventBus: eventBus, + influxDBClient: influxdbClient, } node.BaseService = *service.NewBaseService(logger, "Node", node) @@ -1085,16 +1103,22 @@ func (n *Node) OnStop() { n.Logger.Error("Prometheus HTTP server Shutdown", "err", err) } } + if n.blockStore != nil { if err := n.blockStore.Close(); err != nil { n.Logger.Error("problem closing blockstore", "err", err) } } + if n.stateStore != nil { if err := n.stateStore.Close(); err != nil { n.Logger.Error("problem closing statestore", "err", err) } } + + if n.influxDBClient != nil { + n.influxDBClient.Stop() + } } // ConfigureRPC makes sure RPC has all the objects it needs to operate. diff --git a/pkg/trace/README.md b/pkg/trace/README.md new file mode 100644 index 0000000000..208ba5e5ca --- /dev/null +++ b/pkg/trace/README.md @@ -0,0 +1,95 @@ +# trace: push arbitrary trace level data to an influxdb instance + +This package has code to create a client that can be used to push events to an +influxdb instance. It is used to collect trace data from many different nodes in +a network. If there is no URL in the config.toml, then the underlying client is +nil and no points will be written. The provided chainID and nodeID are used to +tag all points. The underlying client is exposed to allow for custom writes, but +the WritePoint method should be used for most cases, as it enforces the schema. + +## Usage and Schema + +To use this package, first create a new client using the `NewClient` function, +then pass that client to the relevant components that need to push events. After +that, you can use the `WritePoint` method to push events to influxdb. In the below +example, we're pushing a point in the consensus reactor to measure exactly when +each step of consensus is reached for each node. + +```go +if cs.eventCollector.IsCollecting() { + cs.eventCollector.WritePoint("consensus", map[string]interface{}{ + "roundData": []interface{}{rs.Height, rs.Round, rs.Step}, + }) +} +``` + +Using this method enforces the typical schema, where we are tagging (aka +indexing) each point by the chain-id and the node-id, then adding the local time +of the creation of the event. If you need to push a custom point, you can use +the underlying client directly. See influxdb2.WriteAPI for more details. + +### Schema + +All points in influxdb are divided into a key value pair per field. These kvs +are indexed first by a "measurement", which is used as a "table" in other dbs. +Additional indexes can also be added, we're using the chain-id and node-id here. +This allows for us to quickly query for trace data for a specific chain and/or +node. + +```flux +from(bucket: "e2e") + |> range(start: -1h) + |> filter( + fn: (r) => r["_measurement"] == "consensus" + and r.chain_id == "ci-YREG8X" + and r.node_id == "0b529c309608172a29c49979394734260b42acfb" + ) +``` + + +### Running a node with remote tracing on + +Tracing will only occur if an influxdb URL in specified either directly in the +`config.toml` or as flags provided to the start sub command. + +configure in the config.toml + +```toml +####################################################### +### Instrumentation Configuration Options ### +####################################################### +[instrumentation] + +... + +# The URL of the influxdb instance to use for remote event +# collection. If empty, remote event collection is disabled. +influx_url = "http://your-influx-ip:8086/" + +# The influxdb token to use for remote event collection. +influx_token = "your-token" + +# The influxdb bucket to use for remote event collection. +influx_bucket = "e2e" + +# The influxdb org to use for event remote collection. +influx_org = "celestia" + +# The size of the batches that are sent to the database. +influx_batch_size = 20 +``` + +or +```sh +celestia-appd start --influxdb-url=http://your-influx-ip:8086/ --influxdb-token="your-token" +``` + +### e2e tests + +To push events from e2e tests, we only need to specify the URL and the token via +the cli. + +```bash +cd test/e2e +make && ./build/runner -f ./networks/ci.toml --influxdb-url=http://your-influx-ip:8086/ --influxdb-token="your-token" +``` diff --git a/pkg/trace/client.go b/pkg/trace/client.go new file mode 100644 index 0000000000..a3939a88a8 --- /dev/null +++ b/pkg/trace/client.go @@ -0,0 +1,148 @@ +package trace + +import ( + "context" + "fmt" + "time" + + influxdb2 "github.com/influxdata/influxdb-client-go/v2" + "github.com/influxdata/influxdb-client-go/v2/api/write" + "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/libs/log" +) + +const ( + NodeIDTag = "node_id" + ChainIDTag = "chain_id" +) + +// EventCollectorConfig is the influxdb client configuration used for +// collecting events. +type EventCollectorConfig struct { + // URL is the influxdb url. + URL string `mapstructure:"influx_url"` + // Token is the influxdb token. + Token string `mapstructure:"influx_token"` + // Org is the influxdb organization. + Org string `mapstructure:"influx_org"` + // Bucket is the influxdb bucket. + Bucket string `mapstructure:"influx_bucket"` + // BatchSize is the number of points to write in a single batch. + BatchSize int `mapstructure:"influx_batch_size"` +} + +// DefaultEventCollectorConfig returns the default configuration. +func DefaultEventCollectorConfig() EventCollectorConfig { + return EventCollectorConfig{ + URL: "", + Org: "celestia", + Bucket: "e2e", + BatchSize: 10, + } +} + +// Client is an influxdb client that can be used to push events to influxdb. It +// is used to collect trace data from many different nodes in a network. If +// there is no URL in the config.toml, then the underlying client is nil and no +// points will be written. The provided chainID and nodeID are used to tag all +// points. The underlying client is exposed to allow for custom writes, but the +// WritePoint method should be used for most cases, as it enforces the schema. +type Client struct { + ctx context.Context + cancel context.CancelFunc + cfg *config.InstrumentationConfig + + // chainID is added as a tag all points + chainID string + + // nodeID is added as a tag all points + nodeID string + + // Client is the influxdb client. This field is nil if no connection is + // established. + Client influxdb2.Client +} + +// Stop closes the influxdb client. +func (c *Client) Stop() { + c.cancel() + if c.Client == nil { + return + } + writeAPI := c.Client.WriteAPI(c.cfg.InfluxOrg, c.cfg.InfluxBucket) + writeAPI.Flush() + c.Client.Close() +} + +// NewClient creates a new influxdb client using the provided config. If there +// is no URL configured, then the underlying client will be nil, and each +// attempt to write a point will do nothing. The provided chainID and nodeID are +// used to tag all points. +func NewClient(cfg *config.InstrumentationConfig, logger log.Logger, chainID, nodeID string) (*Client, error) { + ctx, cancel := context.WithCancel(context.Background()) + cli := &Client{ + cfg: cfg, + Client: nil, + ctx: ctx, + cancel: cancel, + chainID: chainID, + nodeID: nodeID, + } + if cfg == nil || cfg.InfluxURL == "" { + return cli, nil + } + cli.Client = influxdb2.NewClientWithOptions( + cfg.InfluxURL, + cfg.InfluxToken, + influxdb2.DefaultOptions(). + SetBatchSize(uint(cfg.InfluxBatchSize)), + ) + ctx, cancel = context.WithTimeout(ctx, 3*time.Second) + defer cancel() + alive, err := cli.Client.Ping(ctx) + if err != nil { + return nil, err + } + if !alive { + return nil, fmt.Errorf("failure to ping configured influxdb: %s", cfg.InfluxURL) + } + logger.Info("connected to influxdb", "url", cfg.InfluxURL) + go cli.logErrors(logger) + return cli, nil +} + +// logErrors empties the writeAPI error channel and logs any errors. +func (c *Client) logErrors(logger log.Logger) { + writeAPI := c.Client.WriteAPI(c.cfg.InfluxOrg, c.cfg.InfluxBucket) + for { + select { + case err := <-writeAPI.Errors(): + logger.Error("event collector: influxdb write error", "err", err) + case <-c.ctx.Done(): + return + } + } +} + +// IsCollecting returns true if the client is collecting events. +func (c *Client) IsCollecting() bool { + return c.Client != nil +} + +// WritePoint async writes a point to influxdb. To enforce the schema, it +// automatically adds the chain_id and node_id tags, along with setting the +// timestamp to the current time. If the underlying client is nil, it does +// nothing. The "table" arg is used as the influxdb "measurement" for the point. +// If other tags are needed, use WriteCustomPoint. +func (c *Client) WritePoint(table string, fields map[string]interface{}) { + if !c.IsCollecting() { + return + } + writeAPI := c.Client.WriteAPI(c.cfg.InfluxOrg, c.cfg.InfluxBucket) + tags := map[string]string{ + NodeIDTag: c.nodeID, + ChainIDTag: c.chainID, + } + p := write.NewPoint(table, tags, fields, time.Now()) + writeAPI.WritePoint(p) +} diff --git a/pkg/trace/doc.go b/pkg/trace/doc.go new file mode 100644 index 0000000000..9372af5839 --- /dev/null +++ b/pkg/trace/doc.go @@ -0,0 +1,101 @@ +/* +# trace: push arbitrary trace level data to an influxdb instance + +This package has code to create a client that can be used to push events to an +influxdb instance. It is used to collect trace data from many different nodes in +a network. If there is no URL in the config.toml, then the underlying client is +nil and no points will be written. The provided chainID and nodeID are used to +tag all points. The underlying client is exposed to allow for custom writes, but +the WritePoint method should be used for most cases, as it enforces the schema. + +## Usage and Schema + +To use this package, first create a new client using the `NewClient` function, +then pass that client to the relevant components that need to push events. After +that, you can use the `WritePoint` method to push events to influxdb. In the below +example, we're pushing a point in the consensus reactor to measure exactly when +each step of consensus is reached for each node. + +```go + + if cs.eventCollector.IsCollecting() { + cs.eventCollector.WritePoint("consensus", map[string]interface{}{ + "roundData": []interface{}{rs.Height, rs.Round, rs.Step}, + }) + } + +``` + +Using this method enforces the typical schema, where we are tagging (aka +indexing) each point by the chain-id and the node-id, then adding the local time +of the creation of the event. If you need to push a custom point, you can use +the underlying client directly. See influxdb2.WriteAPI for more details. + +### Schema + +All points in influxdb are divided into a key value pair per field. These kvs +are indexed first by a "measurement", which is used as a "table" in other dbs. +Additional indexes can also be added, we're using the chain-id and node-id here. +This allows for us to quickly query for trace data for a specific chain and/or +node. + +```flux +from(bucket: "e2e") + + |> range(start: -1h) + |> filter( + fn: (r) => r["_measurement"] == "consensus" + and r.chain_id == "ci-YREG8X" + and r.node_id == "0b529c309608172a29c49979394734260b42acfb" + ) + +``` + +### Running a node with remote tracing on + +Tracing will only occur if an influxdb URL in specified either directly in the +`config.toml` or as flags provided to the start sub command. + +configure in the config.toml + +```toml +####################################################### +### Instrumentation Configuration Options ### +####################################################### +[instrumentation] + +... + +# The URL of the influxdb instance to use for remote event +# collection. If empty, remote event collection is disabled. +influx_url = "http://your-influx-ip:8086/" + +# The influxdb token to use for remote event collection. +influx_token = "your-token" + +# The influxdb bucket to use for remote event collection. +influx_bucket = "e2e" + +# The influxdb org to use for event remote collection. +influx_org = "celestia" + +# The size of the batches that are sent to the database. +influx_batch_size = 20 +``` + +or +```sh +celestia-appd start --influxdb-url=http://your-influx-ip:8086/ --influxdb-token="your-token" +``` + +### e2e tests + +To push events from e2e tests, we only need to specify the URL and the token via +the cli. + +```bash +cd test/e2e +make && ./build/runner -f ./networks/ci.toml --influxdb-url=http://your-influx-ip:8086/ --influxdb-token="your-token" +``` +*/ +package trace diff --git a/pkg/trace/flags.go b/pkg/trace/flags.go new file mode 100644 index 0000000000..e56ecc3fda --- /dev/null +++ b/pkg/trace/flags.go @@ -0,0 +1,8 @@ +package trace + +const ( + FlagInfluxDBURL = "influxdb-url" + FlagInfluxDBToken = "influxdb-token" + FlagInfluxDBURLDescription = "URL of the InfluxDB instance to use for arbitrary data collection. If not specified, data will not be collected" + FlagInfluxDBTokenDescription = "Token to use when writing to the InfluxDB instance. Must be specified if 'influxdb-url' is specified" +) diff --git a/test/e2e/pkg/infrastructure.go b/test/e2e/pkg/infrastructure.go index 2fc0e4bac6..a9e1abfa5d 100644 --- a/test/e2e/pkg/infrastructure.go +++ b/test/e2e/pkg/infrastructure.go @@ -32,6 +32,14 @@ type InfrastructureData struct { // Network is the CIDR notation range of IP addresses that all of the instances' // IP addresses are expected to be within. Network string `json:"network"` + + // InfluxDBURL is the URL of the InfluxDB instance to use for arbitrary data + // collection. If not specified, data will not be collected. + InfluxDBURL string `json:"influxdb_url,omitempty"` + + // InfluxDBToken is the token to use when writing to the InfluxDB instance. + // Must be specified if 'influxdb-url' is specified. + InfluxDBToken string `json:"influxdb_token,omitempty"` } // InstanceData contains the relevant information for a machine instance backing diff --git a/test/e2e/pkg/testnet.go b/test/e2e/pkg/testnet.go index 97afc394ef..16f8c1140f 100644 --- a/test/e2e/pkg/testnet.go +++ b/test/e2e/pkg/testnet.go @@ -15,6 +15,7 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/secp256k1" + tmrand "github.com/tendermint/tendermint/libs/rand" rpchttp "github.com/tendermint/tendermint/rpc/client/http" mcs "github.com/tendermint/tendermint/test/maverick/consensus" ) @@ -88,6 +89,8 @@ type Node struct { PersistentPeers []*Node Perturbations []Perturbation Misbehaviors map[int64]string + InfluxDBURL string + InfluxDBToken string } // LoadTestnet loads a testnet from a manifest file, using the filename to @@ -105,7 +108,7 @@ func LoadTestnet(manifest Manifest, fname string, ifd InfrastructureData) (*Test } testnet := &Testnet{ - Name: filepath.Base(dir), + Name: filepath.Base(dir) + "-" + tmrand.Str(6), File: fname, Dir: dir, IP: ipNet, @@ -161,6 +164,8 @@ func LoadTestnet(manifest Manifest, fname string, ifd InfrastructureData) (*Test RetainBlocks: nodeManifest.RetainBlocks, Perturbations: []Perturbation{}, Misbehaviors: make(map[int64]string), + InfluxDBURL: ifd.InfluxDBURL, + InfluxDBToken: ifd.InfluxDBToken, } if node.StartAt == testnet.InitialHeight { node.StartAt = 0 // normalize to 0 for initial nodes, since code expects this diff --git a/test/e2e/runner/main.go b/test/e2e/runner/main.go index 20c6a2a6c7..c23d967960 100644 --- a/test/e2e/runner/main.go +++ b/test/e2e/runner/main.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/cobra" "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/pkg/trace" e2e "github.com/tendermint/tendermint/test/e2e/pkg" "github.com/tendermint/tendermint/test/e2e/pkg/infra" "github.com/tendermint/tendermint/test/e2e/pkg/infra/docker" @@ -78,6 +79,19 @@ func NewCLI() *CLI { return fmt.Errorf("unknown infrastructure type '%s'", inft) } + iurl, err := cmd.Flags().GetString(trace.FlagInfluxDBURL) + if err != nil { + return err + } + itoken, err := cmd.Flags().GetString(trace.FlagInfluxDBToken) + if err != nil { + return err + } + if ifd.InfluxDBURL == "" { + ifd.InfluxDBURL = iurl + ifd.InfluxDBToken = itoken + } + testnet, err := e2e.LoadTestnet(m, file, ifd) if err != nil { return fmt.Errorf("loading testnet: %s", err) @@ -160,6 +174,10 @@ func NewCLI() *CLI { cli.root.PersistentFlags().StringP("infrastructure-data", "", "", "path to the json file containing the infrastructure data. Only used if the 'infrastructure-type' is set to a value other than 'docker'") + cli.root.PersistentFlags().String(trace.FlagInfluxDBURL, "", trace.FlagInfluxDBURLDescription) + + cli.root.PersistentFlags().String(trace.FlagInfluxDBToken, "", trace.FlagInfluxDBTokenDescription) + cli.root.Flags().BoolVarP(&cli.preserve, "preserve", "p", false, "Preserves the running of the test net after tests are completed") diff --git a/test/e2e/runner/perturb.go b/test/e2e/runner/perturb.go index f47aa72bfc..bd13ce0106 100644 --- a/test/e2e/runner/perturb.go +++ b/test/e2e/runner/perturb.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "path/filepath" "time" "github.com/tendermint/tendermint/libs/log" @@ -27,14 +28,16 @@ func Perturb(testnet *e2e.Testnet) error { // after recovering. func PerturbNode(node *e2e.Node, perturbation e2e.Perturbation) (*rpctypes.ResultStatus, error) { testnet := node.Testnet + baseDir := filepath.Base(testnet.Dir) + testnetName := fmt.Sprintf("%s_%s", baseDir, testnet.Name) switch perturbation { case e2e.PerturbationDisconnect: logger.Info("perturb node", "msg", log.NewLazySprintf("Disconnecting node %v...", node.Name)) - if err := execDocker("network", "disconnect", testnet.Name+"_"+testnet.Name, node.Name); err != nil { + if err := execDocker("network", "disconnect", testnetName, node.Name); err != nil { return nil, err } time.Sleep(10 * time.Second) - if err := execDocker("network", "connect", testnet.Name+"_"+testnet.Name, node.Name); err != nil { + if err := execDocker("network", "connect", testnetName, node.Name); err != nil { return nil, err } diff --git a/test/e2e/runner/setup.go b/test/e2e/runner/setup.go index 4ead33a779..dd4964c9f0 100644 --- a/test/e2e/runner/setup.go +++ b/test/e2e/runner/setup.go @@ -168,6 +168,11 @@ func MakeConfig(node *e2e.Node) (*config.Config, error) { cfg.DBBackend = node.Database cfg.StateSync.DiscoveryTime = 5 * time.Second + cfg.Instrumentation.InfluxOrg = "celestia" + cfg.Instrumentation.InfluxBucket = "e2e" + cfg.Instrumentation.InfluxURL = node.InfluxDBURL + cfg.Instrumentation.InfluxToken = node.InfluxDBToken + switch node.ABCIProtocol { case e2e.ProtocolUNIX: cfg.ProxyApp = AppAddressUNIX diff --git a/test/e2e/runner/start.go b/test/e2e/runner/start.go index 0dab98f22d..bcb8a6a7b8 100644 --- a/test/e2e/runner/start.go +++ b/test/e2e/runner/start.go @@ -6,6 +6,7 @@ import ( "time" "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/p2p" e2e "github.com/tendermint/tendermint/test/e2e/pkg" ) @@ -49,7 +50,8 @@ func Start(testnet *e2e.Testnet) error { if _, err := waitForNode(node, 0, 15*time.Second); err != nil { return err } - logger.Info("start", "msg", log.NewLazySprintf("Node %v up on http://127.0.0.1:%v", node.Name, node.ProxyPort)) + nid := p2p.NodeKey{PrivKey: node.NodeKey} + logger.Info("start", "msg", log.NewLazySprintf("Node %v up on http://127.0.0.1:%v chain-id %s node-id %s", node.Name, node.ProxyPort, testnet.Name, nid.ID())) } networkHeight := testnet.InitialHeight