From 6482c18da2c72954cf08240d4243527bac572dcc Mon Sep 17 00:00:00 2001 From: Morgan Date: Thu, 2 May 2024 18:36:57 +0100 Subject: [PATCH] chore(telemetry): move configuration to node config (#2021) This PR moves Telemetry configuration to the centralised node config. h/t to @albttx for identifying this. --- gno.land/cmd/gnoland/start.go | 26 +++------------------ tm2/pkg/bft/config/config.go | 4 ++++ tm2/pkg/telemetry/README.md | 14 +++++------ tm2/pkg/telemetry/config/config.go | 27 ++++++++++++++++++++++ tm2/pkg/telemetry/init.go | 36 +++++++++++++---------------- tm2/pkg/telemetry/metrics/init.go | 4 ++-- tm2/pkg/telemetry/options.go | 35 ---------------------------- tm2/pkg/telemetry/options/config.go | 8 ------- 8 files changed, 58 insertions(+), 96 deletions(-) create mode 100644 tm2/pkg/telemetry/config/config.go delete mode 100644 tm2/pkg/telemetry/options.go delete mode 100644 tm2/pkg/telemetry/options/config.go diff --git a/gno.land/cmd/gnoland/start.go b/gno.land/cmd/gnoland/start.go index 0cbbc6cb36d..aec69d5b338 100644 --- a/gno.land/cmd/gnoland/start.go +++ b/gno.land/cmd/gnoland/start.go @@ -5,7 +5,6 @@ import ( "errors" "flag" "fmt" - "os" "path/filepath" "strings" "time" @@ -219,12 +218,6 @@ func execStart(c *startCfg, io commands.IO) error { loadCfgErr error ) - // Attempt to initialize telemetry. If the environment variables required to initialize - // telemetry are not set, then the initialization will do nothing. - if err := initTelemetry(); err != nil { - return fmt.Errorf("error initializing telemetry: %w", err) - } - // Set the node configuration if c.nodeConfigPath != "" { // Load the node configuration @@ -254,6 +247,9 @@ func execStart(c *startCfg, io commands.IO) error { // Wrap the zap logger logger := log.ZapLoggerToSlog(zapLogger) + // Initialize telemetry + telemetry.Init(*cfg.Telemetry) + // Write genesis file if missing. // NOTE: this will be dropped in a PR that resolves issue #1886: // https://github.com/gnolang/gno/issues/1886 @@ -399,19 +395,3 @@ func getTxEventStoreConfig(c *startCfg) (*eventstorecfg.Config, error) { return cfg, nil } - -func initTelemetry() error { - var options []telemetry.Option - - if os.Getenv("TELEM_METRICS_ENABLED") == "true" { - options = append(options, telemetry.WithOptionMetricsEnabled()) - } - - // The string options can be added by default. Their absence would yield the same result - // as if the option were excluded altogether. - options = append(options, telemetry.WithOptionMeterName(os.Getenv("TELEM_METER_NAME"))) - options = append(options, telemetry.WithOptionExporterEndpoint(os.Getenv("TELEM_EXPORTER_ENDPOINT"))) - options = append(options, telemetry.WithOptionServiceName(os.Getenv("TELEM_SERVICE_NAME"))) - - return telemetry.Init(options...) -} diff --git a/tm2/pkg/bft/config/config.go b/tm2/pkg/bft/config/config.go index 117ce36e96b..e863e1ebcb6 100644 --- a/tm2/pkg/bft/config/config.go +++ b/tm2/pkg/bft/config/config.go @@ -16,6 +16,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/errors" osm "github.com/gnolang/gno/tm2/pkg/os" p2p "github.com/gnolang/gno/tm2/pkg/p2p/config" + telemetry "github.com/gnolang/gno/tm2/pkg/telemetry/config" ) var ( @@ -51,6 +52,7 @@ type Config struct { Mempool *mem.MempoolConfig `toml:"mempool" comment:"##### mempool configuration options #####"` Consensus *cns.ConsensusConfig `toml:"consensus" comment:"##### consensus configuration options #####"` TxEventStore *eventstore.Config `toml:"tx_event_store" comment:"##### event store #####"` + Telemetry *telemetry.Config `toml:"telemetry" comment:"##### node telemetry #####"` } // DefaultConfig returns a default configuration for a Tendermint node @@ -62,6 +64,7 @@ func DefaultConfig() *Config { Mempool: mem.DefaultMempoolConfig(), Consensus: cns.DefaultConsensusConfig(), TxEventStore: eventstore.DefaultEventStoreConfig(), + Telemetry: telemetry.DefaultTelemetryConfig(), } } @@ -138,6 +141,7 @@ func TestConfig() *Config { Mempool: mem.TestMempoolConfig(), Consensus: cns.TestConsensusConfig(), TxEventStore: eventstore.DefaultEventStoreConfig(), + Telemetry: telemetry.TestTelemetryConfig(), } } diff --git a/tm2/pkg/telemetry/README.md b/tm2/pkg/telemetry/README.md index f0cbf26c5e4..cadaecc89ab 100644 --- a/tm2/pkg/telemetry/README.md +++ b/tm2/pkg/telemetry/README.md @@ -1,13 +1,11 @@ # Telemetry -The purpose of this package is to provide a way to easily integrate OpenTelemetry Protocol (OTLP) metrics collection into our codebase. +The purpose of this package is to provide a way to easily integrate OpenTelemetry Protocol (OTLP) metrics collection into a Tendermint 2 node. -## Configure environment variables -Metrics can be enabled using environment variables. The following variables are supported: -- `TELEM_METRICS_ENABLED`: setting to `true` will enable metrics collection -- `TELEM_METER_NAME`: optionally set the meter name; the default is `gno.land` -- `TELEM_SERVICE_NAME`: optionally set the service name; the default is `gno.land` -- `TELEM_EXPORTER_ENDPOINT`: required; this is the endpoint to export metrics to, like a local OTEL collector +## Configure Telemetry + +Telemetry can be regularly configured within the TM2 node through the +`[telemetry]` section. It is disabled by default. ## OTEL configuration There are many ways configure the OTEL pipeline for exporting metrics. Here is an example of how a local OTEL collector can be configured to send metrics to Grafana Cloud. This is an optional step and can be highly customized. @@ -40,4 +38,4 @@ Collector exporter environment variables, including those for authentication, ca ## Resources - https://opentelemetry.io/docs/collector/ -- https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/setup/collector/ \ No newline at end of file +- https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/setup/collector/ diff --git a/tm2/pkg/telemetry/config/config.go b/tm2/pkg/telemetry/config/config.go new file mode 100644 index 00000000000..96c31b48cfd --- /dev/null +++ b/tm2/pkg/telemetry/config/config.go @@ -0,0 +1,27 @@ +// Package config contains the configuration types and helpers for the telemetry +// package. +package config + +// Config is the configuration struct for the tm2 telemetry package. +type Config struct { + MetricsEnabled bool `toml:"enabled"` + MeterName string `toml:"meter_name"` + ServiceName string `toml:"service_name"` + ExporterEndpoint string `toml:"exporter_endpoint" comment:"the endpoint to export metrics to, like a local OpenTelemetry collector"` +} + +// DefaultTelemetryConfig is the default configuration used for the node. +func DefaultTelemetryConfig() *Config { + return &Config{ + MetricsEnabled: false, + MeterName: "gno.land", + ServiceName: "gno.land", + ExporterEndpoint: "", + } +} + +// TestTelemetryConfig is the test configuration. Currently it is an alias for +// [DefaultTelemetryConfig]. +func TestTelemetryConfig() *Config { + return DefaultTelemetryConfig() +} diff --git a/tm2/pkg/telemetry/init.go b/tm2/pkg/telemetry/init.go index b50a7ab5659..8d31c6268f8 100644 --- a/tm2/pkg/telemetry/init.go +++ b/tm2/pkg/telemetry/init.go @@ -4,37 +4,33 @@ package telemetry // https://github.com/open-telemetry/opentelemetry-go/blob/main/example/prometheus/main.go import ( + "sync/atomic" + + "github.com/gnolang/gno/tm2/pkg/telemetry/config" "github.com/gnolang/gno/tm2/pkg/telemetry/metrics" - "github.com/gnolang/gno/tm2/pkg/telemetry/options" ) -const ( - defaultMeterName = "gno.land" - defaultServiceName = "gno.land" +var ( + globalConfig config.Config + globalConfigSet atomic.Bool ) -var config options.Config - // MetricsEnabled returns true if metrics have been initialized. func MetricsEnabled() bool { - return config.MetricsEnabled + return globalConfig.MetricsEnabled } -// Init will initialize metrics with the options provided. This function may also initialize tracing when -// this is something that we want to support. -func Init(options ...Option) error { - config.MeterName = defaultMeterName - config.ServiceName = defaultServiceName - for _, opt := range options { - opt(&config) +// Init sets the configuration for telemetry to c, and if telemetry is enabled, +// starts tracking. +// Init may only be called once. Multiple calls to Init will panic. +func Init(c config.Config) error { + if !globalConfigSet.CompareAndSwap(false, true) { + panic("telemetry configuration has already been set and initialised") } - + globalConfig = c // Initialize metrics to be collected. - if config.MetricsEnabled { - if err := metrics.Init(config); err != nil { - return err - } + if c.MetricsEnabled { + return metrics.Init(c) } - return nil } diff --git a/tm2/pkg/telemetry/metrics/init.go b/tm2/pkg/telemetry/metrics/init.go index d97805894a0..ac67a8d71ce 100644 --- a/tm2/pkg/telemetry/metrics/init.go +++ b/tm2/pkg/telemetry/metrics/init.go @@ -3,8 +3,8 @@ package metrics import ( "context" + "github.com/gnolang/gno/tm2/pkg/telemetry/config" "github.com/gnolang/gno/tm2/pkg/telemetry/exporter" - "github.com/gnolang/gno/tm2/pkg/telemetry/options" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" "go.opentelemetry.io/otel/metric" @@ -19,7 +19,7 @@ var ( BuildBlockTimer metric.Int64Histogram ) -func Init(config options.Config) error { +func Init(config config.Config) error { if config.ExporterEndpoint == "" { return exporter.ErrEndpointNotSet } diff --git a/tm2/pkg/telemetry/options.go b/tm2/pkg/telemetry/options.go deleted file mode 100644 index 2e3d629812e..00000000000 --- a/tm2/pkg/telemetry/options.go +++ /dev/null @@ -1,35 +0,0 @@ -package telemetry - -import "github.com/gnolang/gno/tm2/pkg/telemetry/options" - -type Option func(*options.Config) - -func WithOptionMetricsEnabled() Option { - return func(c *options.Config) { - c.MetricsEnabled = true - } -} - -func WithOptionMeterName(meterName string) Option { - return func(c *options.Config) { - if meterName != "" { - c.MeterName = meterName - } - } -} - -func WithOptionExporterEndpoint(exporterEndpoint string) Option { - return func(c *options.Config) { - if exporterEndpoint != "" { - c.ExporterEndpoint = exporterEndpoint - } - } -} - -func WithOptionServiceName(serviceName string) Option { - return func(c *options.Config) { - if serviceName != "" { - c.ServiceName = serviceName - } - } -} diff --git a/tm2/pkg/telemetry/options/config.go b/tm2/pkg/telemetry/options/config.go deleted file mode 100644 index 80d07e588aa..00000000000 --- a/tm2/pkg/telemetry/options/config.go +++ /dev/null @@ -1,8 +0,0 @@ -package options - -type Config struct { - MetricsEnabled bool - MeterName string - ServiceName string - ExporterEndpoint string -}