depot/packages/networking/ipfs-cluster/observations/config.go

269 lines
7 KiB
Go

package observations
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/kelseyhightower/envconfig"
ma "github.com/multiformats/go-multiaddr"
"github.com/ipfs-cluster/ipfs-cluster/config"
)
const metricsConfigKey = "metrics"
const tracingConfigKey = "tracing"
const metricsEnvConfigKey = "cluster_metrics"
const tracingEnvConfigKey = "cluster_tracing"
// Default values for this Config.
const (
DefaultEnableStats = false
DefaultPrometheusEndpoint = "/ip4/127.0.0.1/tcp/8888"
DefaultReportingInterval = 2 * time.Second
DefaultEnableTracing = false
DefaultJaegerAgentEndpoint = "/ip4/0.0.0.0/udp/6831"
DefaultSamplingProb = 0.3
DefaultServiceName = "cluster-daemon"
)
// MetricsConfig configures metrics collection.
type MetricsConfig struct {
config.Saver
EnableStats bool
PrometheusEndpoint ma.Multiaddr
ReportingInterval time.Duration
}
type jsonMetricsConfig struct {
EnableStats bool `json:"enable_stats"`
PrometheusEndpoint string `json:"prometheus_endpoint"`
ReportingInterval string `json:"reporting_interval"`
}
// ConfigKey provides a human-friendly identifier for this type of Config.
func (cfg *MetricsConfig) ConfigKey() string {
return metricsConfigKey
}
// Default sets the fields of this Config to sensible values.
func (cfg *MetricsConfig) Default() error {
cfg.EnableStats = DefaultEnableStats
endpointAddr, _ := ma.NewMultiaddr(DefaultPrometheusEndpoint)
cfg.PrometheusEndpoint = endpointAddr
cfg.ReportingInterval = DefaultReportingInterval
return nil
}
// ApplyEnvVars fills in any Config fields found
// as environment variables.
func (cfg *MetricsConfig) ApplyEnvVars() error {
jcfg := cfg.toJSONConfig()
err := envconfig.Process(metricsEnvConfigKey, jcfg)
if err != nil {
return err
}
return cfg.applyJSONConfig(jcfg)
}
// Validate checks that the fields of this Config have working values,
// at least in appearance.
func (cfg *MetricsConfig) Validate() error {
if cfg.EnableStats {
if cfg.PrometheusEndpoint == nil {
return errors.New("metrics.prometheus_endpoint is undefined")
}
if cfg.ReportingInterval < 0 {
return errors.New("metrics.reporting_interval is invalid")
}
}
return nil
}
// LoadJSON sets the fields of this Config to the values defined by the JSON
// representation of it, as generated by ToJSON.
func (cfg *MetricsConfig) LoadJSON(raw []byte) error {
jcfg := &jsonMetricsConfig{}
err := json.Unmarshal(raw, jcfg)
if err != nil {
logger.Error("Error unmarshaling observations config")
return err
}
cfg.Default()
return cfg.applyJSONConfig(jcfg)
}
func (cfg *MetricsConfig) applyJSONConfig(jcfg *jsonMetricsConfig) error {
err := cfg.loadMetricsOptions(jcfg)
if err != nil {
return err
}
return cfg.Validate()
}
func (cfg *MetricsConfig) loadMetricsOptions(jcfg *jsonMetricsConfig) error {
cfg.EnableStats = jcfg.EnableStats
endpointAddr, err := ma.NewMultiaddr(jcfg.PrometheusEndpoint)
if err != nil {
return fmt.Errorf("loadMetricsOptions: PrometheusEndpoint multiaddr: %v", err)
}
cfg.PrometheusEndpoint = endpointAddr
return config.ParseDurations(
metricsConfigKey,
&config.DurationOpt{
Duration: jcfg.ReportingInterval,
Dst: &cfg.ReportingInterval,
Name: "metrics.reporting_interval",
},
)
}
// ToJSON generates a human-friendly JSON representation of this Config.
func (cfg *MetricsConfig) ToJSON() ([]byte, error) {
jcfg := cfg.toJSONConfig()
return config.DefaultJSONMarshal(jcfg)
}
func (cfg *MetricsConfig) toJSONConfig() *jsonMetricsConfig {
return &jsonMetricsConfig{
EnableStats: cfg.EnableStats,
PrometheusEndpoint: cfg.PrometheusEndpoint.String(),
ReportingInterval: cfg.ReportingInterval.String(),
}
}
// ToDisplayJSON returns JSON config as a string.
func (cfg *MetricsConfig) ToDisplayJSON() ([]byte, error) {
return config.DisplayJSON(cfg.toJSONConfig())
}
// TracingConfig configures tracing.
type TracingConfig struct {
config.Saver
EnableTracing bool
JaegerAgentEndpoint ma.Multiaddr
SamplingProb float64
ServiceName string
ClusterID string
ClusterPeername string
}
type jsonTracingConfig struct {
EnableTracing bool `json:"enable_tracing"`
JaegerAgentEndpoint string `json:"jaeger_agent_endpoint"`
SamplingProb float64 `json:"sampling_prob"`
ServiceName string `json:"service_name"`
}
// ConfigKey provides a human-friendly identifier for this type of Config.
func (cfg *TracingConfig) ConfigKey() string {
return tracingConfigKey
}
// Default sets the fields of this Config to sensible values.
func (cfg *TracingConfig) Default() error {
cfg.EnableTracing = DefaultEnableTracing
agentAddr, _ := ma.NewMultiaddr(DefaultJaegerAgentEndpoint)
cfg.JaegerAgentEndpoint = agentAddr
cfg.SamplingProb = DefaultSamplingProb
cfg.ServiceName = DefaultServiceName
return nil
}
// ApplyEnvVars fills in any Config fields found
// as environment variables.
func (cfg *TracingConfig) ApplyEnvVars() error {
jcfg := cfg.toJSONConfig()
err := envconfig.Process(tracingEnvConfigKey, jcfg)
if err != nil {
return err
}
return cfg.applyJSONConfig(jcfg)
}
// Validate checks that the fields of this Config have working values,
// at least in appearance.
func (cfg *TracingConfig) Validate() error {
if cfg.EnableTracing {
if cfg.JaegerAgentEndpoint == nil {
return errors.New("tracing.jaeger_agent_endpoint is undefined")
}
if cfg.SamplingProb < 0 {
return errors.New("tracing.sampling_prob is invalid")
}
}
return nil
}
// LoadJSON sets the fields of this Config to the values defined by the JSON
// representation of it, as generated by ToJSON.
func (cfg *TracingConfig) LoadJSON(raw []byte) error {
jcfg := &jsonTracingConfig{}
err := json.Unmarshal(raw, jcfg)
if err != nil {
logger.Error("Error unmarshaling observations config")
return err
}
cfg.Default()
return cfg.applyJSONConfig(jcfg)
}
func (cfg *TracingConfig) applyJSONConfig(jcfg *jsonTracingConfig) error {
err := cfg.loadTracingOptions(jcfg)
if err != nil {
return err
}
return cfg.Validate()
}
func (cfg *TracingConfig) loadTracingOptions(jcfg *jsonTracingConfig) error {
cfg.EnableTracing = jcfg.EnableTracing
agentAddr, err := ma.NewMultiaddr(jcfg.JaegerAgentEndpoint)
if err != nil {
return fmt.Errorf("loadTracingOptions: JaegerAgentEndpoint multiaddr: %v", err)
}
cfg.JaegerAgentEndpoint = agentAddr
cfg.SamplingProb = jcfg.SamplingProb
cfg.ServiceName = jcfg.ServiceName
return nil
}
// ToJSON generates a human-friendly JSON representation of this Config.
func (cfg *TracingConfig) ToJSON() ([]byte, error) {
jcfg := cfg.toJSONConfig()
return config.DefaultJSONMarshal(jcfg)
}
func (cfg *TracingConfig) toJSONConfig() *jsonTracingConfig {
return &jsonTracingConfig{
EnableTracing: cfg.EnableTracing,
JaegerAgentEndpoint: cfg.JaegerAgentEndpoint.String(),
SamplingProb: cfg.SamplingProb,
ServiceName: cfg.ServiceName,
}
}
// ToDisplayJSON returns JSON config as a string.
func (cfg *TracingConfig) ToDisplayJSON() ([]byte, error) {
return config.DisplayJSON(cfg.toJSONConfig())
}