270 lines
7 KiB
Go
270 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())
|
||
|
}
|