diff options
Diffstat (limited to 'plugins/metrics')
-rw-r--r-- | plugins/metrics/config.go | 140 | ||||
-rw-r--r-- | plugins/metrics/config_test.go | 89 | ||||
-rw-r--r-- | plugins/metrics/doc.go | 1 | ||||
-rw-r--r-- | plugins/metrics/interface.go | 7 | ||||
-rw-r--r-- | plugins/metrics/plugin.go | 242 | ||||
-rw-r--r-- | plugins/metrics/rpc.go | 294 |
6 files changed, 0 insertions, 773 deletions
diff --git a/plugins/metrics/config.go b/plugins/metrics/config.go deleted file mode 100644 index a2835130..00000000 --- a/plugins/metrics/config.go +++ /dev/null @@ -1,140 +0,0 @@ -package metrics - -import ( - "fmt" - - "github.com/prometheus/client_golang/prometheus" -) - -// Config configures metrics service. -type Config struct { - // Address to listen - Address string - - // Collect define application specific metrics. - Collect map[string]Collector -} - -type NamedCollector struct { - // Name of the collector - Name string `json:"name"` - - // Collector structure - Collector `json:"collector"` -} - -// CollectorType represents prometheus collector types -type CollectorType string - -const ( - // Histogram type - Histogram CollectorType = "histogram" - - // Gauge type - Gauge CollectorType = "gauge" - - // Counter type - Counter CollectorType = "counter" - - // Summary type - Summary CollectorType = "summary" -) - -// Collector describes single application specific metric. -type Collector struct { - // Namespace of the metric. - Namespace string `json:"namespace"` - // Subsystem of the metric. - Subsystem string `json:"subsystem"` - // Collector type (histogram, gauge, counter, summary). - Type CollectorType `json:"type"` - // Help of collector. - Help string `json:"help"` - // Labels for vectorized metrics. - Labels []string `json:"labels"` - // Buckets for histogram metric. - Buckets []float64 `json:"buckets"` - // Objectives for the summary opts - Objectives map[float64]float64 `json:"objectives"` -} - -// register application specific metrics. -func (c *Config) getCollectors() (map[string]prometheus.Collector, error) { - if c.Collect == nil { - return nil, nil - } - - collectors := make(map[string]prometheus.Collector) - - for name, m := range c.Collect { - var collector prometheus.Collector - switch m.Type { - case Histogram: - opts := prometheus.HistogramOpts{ - Name: name, - Namespace: m.Namespace, - Subsystem: m.Subsystem, - Help: m.Help, - Buckets: m.Buckets, - } - - if len(m.Labels) != 0 { - collector = prometheus.NewHistogramVec(opts, m.Labels) - } else { - collector = prometheus.NewHistogram(opts) - } - case Gauge: - opts := prometheus.GaugeOpts{ - Name: name, - Namespace: m.Namespace, - Subsystem: m.Subsystem, - Help: m.Help, - } - - if len(m.Labels) != 0 { - collector = prometheus.NewGaugeVec(opts, m.Labels) - } else { - collector = prometheus.NewGauge(opts) - } - case Counter: - opts := prometheus.CounterOpts{ - Name: name, - Namespace: m.Namespace, - Subsystem: m.Subsystem, - Help: m.Help, - } - - if len(m.Labels) != 0 { - collector = prometheus.NewCounterVec(opts, m.Labels) - } else { - collector = prometheus.NewCounter(opts) - } - case Summary: - opts := prometheus.SummaryOpts{ - Name: name, - Namespace: m.Namespace, - Subsystem: m.Subsystem, - Help: m.Help, - Objectives: m.Objectives, - } - - if len(m.Labels) != 0 { - collector = prometheus.NewSummaryVec(opts, m.Labels) - } else { - collector = prometheus.NewSummary(opts) - } - default: - return nil, fmt.Errorf("invalid metric type `%s` for `%s`", m.Type, name) - } - - collectors[name] = collector - } - - return collectors, nil -} - -func (c *Config) InitDefaults() { - if c.Address == "" { - c.Address = "127.0.0.1:2112" - } -} diff --git a/plugins/metrics/config_test.go b/plugins/metrics/config_test.go deleted file mode 100644 index 665ec9cd..00000000 --- a/plugins/metrics/config_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package metrics - -import ( - "bytes" - "testing" - - j "github.com/json-iterator/go" - "github.com/prometheus/client_golang/prometheus" - "github.com/stretchr/testify/assert" -) - -var json = j.ConfigCompatibleWithStandardLibrary - -func Test_Config_Hydrate_Error1(t *testing.T) { - cfg := `{"request": {"From": "Something"}}` - c := &Config{} - f := new(bytes.Buffer) - f.WriteString(cfg) - - err := json.Unmarshal(f.Bytes(), &c) - if err != nil { - t.Fatal(err) - } -} - -func Test_Config_Hydrate_Error2(t *testing.T) { - cfg := `{"dir": "/dir/"` - c := &Config{} - - f := new(bytes.Buffer) - f.WriteString(cfg) - - err := json.Unmarshal(f.Bytes(), &c) - assert.Error(t, err) -} - -func Test_Config_Metrics(t *testing.T) { - cfg := `{ -"collect":{ - "metric1":{"type": "gauge"}, - "metric2":{ "type": "counter"}, - "metric3":{"type": "summary"}, - "metric4":{"type": "histogram"} -} -}` - c := &Config{} - f := new(bytes.Buffer) - f.WriteString(cfg) - - err := json.Unmarshal(f.Bytes(), &c) - if err != nil { - t.Fatal(err) - } - - m, err := c.getCollectors() - assert.NoError(t, err) - - assert.IsType(t, prometheus.NewGauge(prometheus.GaugeOpts{}), m["metric1"]) - assert.IsType(t, prometheus.NewCounter(prometheus.CounterOpts{}), m["metric2"]) - assert.IsType(t, prometheus.NewSummary(prometheus.SummaryOpts{}), m["metric3"]) - assert.IsType(t, prometheus.NewHistogram(prometheus.HistogramOpts{}), m["metric4"]) -} - -func Test_Config_MetricsVector(t *testing.T) { - cfg := `{ -"collect":{ - "metric1":{"type": "gauge","labels":["label"]}, - "metric2":{ "type": "counter","labels":["label"]}, - "metric3":{"type": "summary","labels":["label"]}, - "metric4":{"type": "histogram","labels":["label"]} -} -}` - c := &Config{} - f := new(bytes.Buffer) - f.WriteString(cfg) - - err := json.Unmarshal(f.Bytes(), &c) - if err != nil { - t.Fatal(err) - } - - m, err := c.getCollectors() - assert.NoError(t, err) - - assert.IsType(t, prometheus.NewGaugeVec(prometheus.GaugeOpts{}, []string{}), m["metric1"]) - assert.IsType(t, prometheus.NewCounterVec(prometheus.CounterOpts{}, []string{}), m["metric2"]) - assert.IsType(t, prometheus.NewSummaryVec(prometheus.SummaryOpts{}, []string{}), m["metric3"]) - assert.IsType(t, prometheus.NewHistogramVec(prometheus.HistogramOpts{}, []string{}), m["metric4"]) -} diff --git a/plugins/metrics/doc.go b/plugins/metrics/doc.go deleted file mode 100644 index 1abe097a..00000000 --- a/plugins/metrics/doc.go +++ /dev/null @@ -1 +0,0 @@ -package metrics diff --git a/plugins/metrics/interface.go b/plugins/metrics/interface.go deleted file mode 100644 index 87ba4017..00000000 --- a/plugins/metrics/interface.go +++ /dev/null @@ -1,7 +0,0 @@ -package metrics - -import "github.com/prometheus/client_golang/prometheus" - -type StatProvider interface { - MetricsCollector() []prometheus.Collector -} diff --git a/plugins/metrics/plugin.go b/plugins/metrics/plugin.go deleted file mode 100644 index d285e609..00000000 --- a/plugins/metrics/plugin.go +++ /dev/null @@ -1,242 +0,0 @@ -package metrics - -import ( - "context" - "crypto/tls" - "net/http" - "sync" - "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/spiral/errors" - "github.com/spiral/roadrunner/v2/plugins/config" - "github.com/spiral/roadrunner/v2/plugins/logger" - "golang.org/x/sys/cpu" -) - -const ( - // PluginName declares plugin name. - PluginName = "metrics" - // maxHeaderSize declares max header size for prometheus server - maxHeaderSize = 1024 * 1024 * 100 // 104MB -) - -// Plugin to manage application metrics using Prometheus. -type Plugin struct { - cfg *Config - log logger.Logger - mu sync.Mutex // all receivers are pointers - http *http.Server - collectors sync.Map // all receivers are pointers - registry *prometheus.Registry - - // prometheus Collectors - statProviders []StatProvider -} - -// Init service. -func (p *Plugin) Init(cfg config.Configurer, log logger.Logger) error { - const op = errors.Op("metrics_plugin_init") - if !cfg.Has(PluginName) { - return errors.E(op, errors.Disabled) - } - - err := cfg.UnmarshalKey(PluginName, &p.cfg) - if err != nil { - return errors.E(op, errors.Disabled, err) - } - - p.cfg.InitDefaults() - - p.log = log - p.registry = prometheus.NewRegistry() - - // Default - err = p.registry.Register(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})) - if err != nil { - return errors.E(op, err) - } - - // Default - err = p.registry.Register(collectors.NewGoCollector()) - if err != nil { - return errors.E(op, err) - } - - cl, err := p.cfg.getCollectors() - if err != nil { - return errors.E(op, err) - } - - // Register invocation will be later in the Serve method - for k, v := range cl { - p.collectors.Store(k, v) - } - - p.statProviders = make([]StatProvider, 0, 2) - - return nil -} - -// Register new prometheus collector. -func (p *Plugin) Register(c prometheus.Collector) error { - return p.registry.Register(c) -} - -// Serve prometheus metrics service. -func (p *Plugin) Serve() chan error { - errCh := make(chan error, 1) - - // register Collected stat providers - for i := 0; i < len(p.statProviders); i++ { - sp := p.statProviders[i] - for _, c := range sp.MetricsCollector() { - err := p.registry.Register(c) - if err != nil { - errCh <- err - return errCh - } - } - } - - p.collectors.Range(func(key, value interface{}) bool { - // key - name - // value - prometheus.Collector - c := value.(prometheus.Collector) - if err := p.registry.Register(c); err != nil { - errCh <- err - return false - } - - return true - }) - - var topCipherSuites []uint16 - var defaultCipherSuitesTLS13 []uint16 - - hasGCMAsmAMD64 := cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ - hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL - // Keep in sync with crypto/aes/cipher_s390x.go. - hasGCMAsmS390X := cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) - - hasGCMAsm := hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X - - if hasGCMAsm { - // If AES-GCM hardware is provided then prioritize AES-GCM - // cipher suites. - topCipherSuites = []uint16{ - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - } - defaultCipherSuitesTLS13 = []uint16{ - tls.TLS_AES_128_GCM_SHA256, - tls.TLS_CHACHA20_POLY1305_SHA256, - tls.TLS_AES_256_GCM_SHA384, - } - } else { - // Without AES-GCM hardware, we put the ChaCha20-Poly1305 - // cipher suites first. - topCipherSuites = []uint16{ - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - } - defaultCipherSuitesTLS13 = []uint16{ - tls.TLS_CHACHA20_POLY1305_SHA256, - tls.TLS_AES_128_GCM_SHA256, - tls.TLS_AES_256_GCM_SHA384, - } - } - - DefaultCipherSuites := make([]uint16, 0, 22) - DefaultCipherSuites = append(DefaultCipherSuites, topCipherSuites...) - DefaultCipherSuites = append(DefaultCipherSuites, defaultCipherSuitesTLS13...) - - p.http = &http.Server{ - Addr: p.cfg.Address, - Handler: promhttp.HandlerFor(p.registry, promhttp.HandlerOpts{}), - IdleTimeout: time.Hour * 24, - ReadTimeout: time.Minute * 60, - MaxHeaderBytes: maxHeaderSize, - ReadHeaderTimeout: time.Minute * 60, - WriteTimeout: time.Minute * 60, - TLSConfig: &tls.Config{ - CurvePreferences: []tls.CurveID{ - tls.CurveP256, - tls.CurveP384, - tls.CurveP521, - tls.X25519, - }, - CipherSuites: DefaultCipherSuites, - MinVersion: tls.VersionTLS12, - PreferServerCipherSuites: true, - }, - } - - go func() { - err := p.http.ListenAndServe() - if err != nil && err != http.ErrServerClosed { - errCh <- err - return - } - }() - - return errCh -} - -// Stop prometheus metrics service. -func (p *Plugin) Stop() error { - p.mu.Lock() - defer p.mu.Unlock() - - if p.http != nil { - // timeout is 10 seconds - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - err := p.http.Shutdown(ctx) - if err != nil { - // Function should be Stop() error - p.log.Error("stop error", "error", errors.Errorf("error shutting down the metrics server: error %v", err)) - } - } - return nil -} - -// Collects used to collect all plugins which implement metrics.StatProvider interface (and Named) -func (p *Plugin) Collects() []interface{} { - return []interface{}{ - p.AddStatProvider, - } -} - -// AddStatProvider adds a metrics provider -func (p *Plugin) AddStatProvider(stat StatProvider) error { - p.statProviders = append(p.statProviders, stat) - - return nil -} - -// Name returns user friendly plugin name -func (p *Plugin) Name() string { - return PluginName -} - -// RPC interface satisfaction -func (p *Plugin) RPC() interface{} { - return &rpcServer{ - svc: p, - log: p.log, - } -} - -// Available interface implementation -func (p *Plugin) Available() {} diff --git a/plugins/metrics/rpc.go b/plugins/metrics/rpc.go deleted file mode 100644 index 538cdb78..00000000 --- a/plugins/metrics/rpc.go +++ /dev/null @@ -1,294 +0,0 @@ -package metrics - -import ( - "github.com/prometheus/client_golang/prometheus" - "github.com/spiral/errors" - "github.com/spiral/roadrunner/v2/plugins/logger" -) - -type rpcServer struct { - svc *Plugin - log logger.Logger -} - -// Metric represent single metric produced by the application. -type Metric struct { - // Collector name. - Name string - - // Collector value. - Value float64 - - // Labels associated with metric. Only for vector metrics. Must be provided in a form of label values. - Labels []string -} - -// Add new metric to the designated collector. -func (rpc *rpcServer) Add(m *Metric, ok *bool) error { - const op = errors.Op("metrics_plugin_add") - rpc.log.Info("adding metric", "name", m.Name, "value", m.Value, "labels", m.Labels) - c, exist := rpc.svc.collectors.Load(m.Name) - if !exist { - rpc.log.Error("undefined collector", "collector", m.Name) - return errors.E(op, errors.Errorf("undefined collector %s, try first Declare the desired collector", m.Name)) - } - - switch c := c.(type) { - case prometheus.Gauge: - c.Add(m.Value) - - case *prometheus.GaugeVec: - if len(m.Labels) == 0 { - rpc.log.Error("required labels for collector", "collector", m.Name) - return errors.E(op, errors.Errorf("required labels for collector %s", m.Name)) - } - - gauge, err := c.GetMetricWithLabelValues(m.Labels...) - if err != nil { - rpc.log.Error("failed to get metrics with label values", "collector", m.Name, "labels", m.Labels) - return errors.E(op, err) - } - gauge.Add(m.Value) - case prometheus.Counter: - c.Add(m.Value) - - case *prometheus.CounterVec: - if len(m.Labels) == 0 { - return errors.E(op, errors.Errorf("required labels for collector `%s`", m.Name)) - } - - gauge, err := c.GetMetricWithLabelValues(m.Labels...) - if err != nil { - rpc.log.Error("failed to get metrics with label values", "collector", m.Name, "labels", m.Labels) - return errors.E(op, err) - } - gauge.Add(m.Value) - - default: - return errors.E(op, errors.Errorf("collector %s does not support method `Add`", m.Name)) - } - - // RPC, set ok to true as return value. Need by rpc.Call reply argument - *ok = true - rpc.log.Info("metric successfully added", "name", m.Name, "labels", m.Labels, "value", m.Value) - return nil -} - -// Sub subtract the value from the specific metric (gauge only). -func (rpc *rpcServer) Sub(m *Metric, ok *bool) error { - const op = errors.Op("metrics_plugin_sub") - rpc.log.Info("subtracting value from metric", "name", m.Name, "value", m.Value, "labels", m.Labels) - c, exist := rpc.svc.collectors.Load(m.Name) - if !exist { - rpc.log.Error("undefined collector", "name", m.Name, "value", m.Value, "labels", m.Labels) - return errors.E(op, errors.Errorf("undefined collector %s", m.Name)) - } - if c == nil { - // can it be nil ??? I guess can't - return errors.E(op, errors.Errorf("undefined collector %s", m.Name)) - } - - switch c := c.(type) { - case prometheus.Gauge: - c.Sub(m.Value) - - case *prometheus.GaugeVec: - if len(m.Labels) == 0 { - rpc.log.Error("required labels for collector, but none was provided", "name", m.Name, "value", m.Value) - return errors.E(op, errors.Errorf("required labels for collector %s", m.Name)) - } - - gauge, err := c.GetMetricWithLabelValues(m.Labels...) - if err != nil { - rpc.log.Error("failed to get metrics with label values", "collector", m.Name, "labels", m.Labels) - return errors.E(op, err) - } - gauge.Sub(m.Value) - default: - return errors.E(op, errors.Errorf("collector `%s` does not support method `Sub`", m.Name)) - } - rpc.log.Info("subtracting operation finished successfully", "name", m.Name, "labels", m.Labels, "value", m.Value) - - *ok = true - return nil -} - -// Observe the value (histogram and summary only). -func (rpc *rpcServer) Observe(m *Metric, ok *bool) error { - const op = errors.Op("metrics_plugin_observe") - rpc.log.Info("observing metric", "name", m.Name, "value", m.Value, "labels", m.Labels) - - c, exist := rpc.svc.collectors.Load(m.Name) - if !exist { - rpc.log.Error("undefined collector", "name", m.Name, "value", m.Value, "labels", m.Labels) - return errors.E(op, errors.Errorf("undefined collector %s", m.Name)) - } - if c == nil { - return errors.E(op, errors.Errorf("undefined collector %s", m.Name)) - } - - switch c := c.(type) { - case *prometheus.SummaryVec: - if len(m.Labels) == 0 { - return errors.E(op, errors.Errorf("required labels for collector `%s`", m.Name)) - } - - observer, err := c.GetMetricWithLabelValues(m.Labels...) - if err != nil { - return errors.E(op, err) - } - observer.Observe(m.Value) - - case prometheus.Histogram: - c.Observe(m.Value) - - case *prometheus.HistogramVec: - if len(m.Labels) == 0 { - return errors.E(op, errors.Errorf("required labels for collector `%s`", m.Name)) - } - - observer, err := c.GetMetricWithLabelValues(m.Labels...) - if err != nil { - rpc.log.Error("failed to get metrics with label values", "collector", m.Name, "labels", m.Labels) - return errors.E(op, err) - } - observer.Observe(m.Value) - default: - return errors.E(op, errors.Errorf("collector `%s` does not support method `Observe`", m.Name)) - } - - rpc.log.Info("observe operation finished successfully", "name", m.Name, "labels", m.Labels, "value", m.Value) - - *ok = true - return nil -} - -// Declare is used to register new collector in prometheus -// THE TYPES ARE: -// NamedCollector -> Collector with the name -// bool -> RPC reply value -// RETURNS: -// error -func (rpc *rpcServer) Declare(nc *NamedCollector, ok *bool) error { - const op = errors.Op("metrics_plugin_declare") - rpc.log.Info("declaring new metric", "name", nc.Name, "type", nc.Type, "namespace", nc.Namespace) - _, exist := rpc.svc.collectors.Load(nc.Name) - if exist { - rpc.log.Error("metric with provided name already exist", "name", nc.Name, "type", nc.Type, "namespace", nc.Namespace) - return errors.E(op, errors.Errorf("tried to register existing collector with the name `%s`", nc.Name)) - } - - var collector prometheus.Collector - switch nc.Type { - case Histogram: - opts := prometheus.HistogramOpts{ - Name: nc.Name, - Namespace: nc.Namespace, - Subsystem: nc.Subsystem, - Help: nc.Help, - Buckets: nc.Buckets, - } - - if len(nc.Labels) != 0 { - collector = prometheus.NewHistogramVec(opts, nc.Labels) - } else { - collector = prometheus.NewHistogram(opts) - } - case Gauge: - opts := prometheus.GaugeOpts{ - Name: nc.Name, - Namespace: nc.Namespace, - Subsystem: nc.Subsystem, - Help: nc.Help, - } - - if len(nc.Labels) != 0 { - collector = prometheus.NewGaugeVec(opts, nc.Labels) - } else { - collector = prometheus.NewGauge(opts) - } - case Counter: - opts := prometheus.CounterOpts{ - Name: nc.Name, - Namespace: nc.Namespace, - Subsystem: nc.Subsystem, - Help: nc.Help, - } - - if len(nc.Labels) != 0 { - collector = prometheus.NewCounterVec(opts, nc.Labels) - } else { - collector = prometheus.NewCounter(opts) - } - case Summary: - opts := prometheus.SummaryOpts{ - Name: nc.Name, - Namespace: nc.Namespace, - Subsystem: nc.Subsystem, - Help: nc.Help, - } - - if len(nc.Labels) != 0 { - collector = prometheus.NewSummaryVec(opts, nc.Labels) - } else { - collector = prometheus.NewSummary(opts) - } - - default: - return errors.E(op, errors.Errorf("unknown collector type %s", nc.Type)) - } - - // add collector to sync.Map - rpc.svc.collectors.Store(nc.Name, collector) - // that method might panic, we handle it by recover - err := rpc.svc.Register(collector) - if err != nil { - *ok = false - return errors.E(op, err) - } - - rpc.log.Info("metric successfully added", "name", nc.Name, "type", nc.Type, "namespace", nc.Namespace) - - *ok = true - return nil -} - -// Set the metric value (only for gaude). -func (rpc *rpcServer) Set(m *Metric, ok *bool) (err error) { - const op = errors.Op("metrics_plugin_set") - rpc.log.Info("observing metric", "name", m.Name, "value", m.Value, "labels", m.Labels) - - c, exist := rpc.svc.collectors.Load(m.Name) - if !exist { - return errors.E(op, errors.Errorf("undefined collector %s", m.Name)) - } - if c == nil { - return errors.E(op, errors.Errorf("undefined collector %s", m.Name)) - } - - switch c := c.(type) { - case prometheus.Gauge: - c.Set(m.Value) - - case *prometheus.GaugeVec: - if len(m.Labels) == 0 { - rpc.log.Error("required labels for collector", "collector", m.Name) - return errors.E(op, errors.Errorf("required labels for collector %s", m.Name)) - } - - gauge, err := c.GetMetricWithLabelValues(m.Labels...) - if err != nil { - rpc.log.Error("failed to get metrics with label values", "collector", m.Name, "labels", m.Labels) - return errors.E(op, err) - } - gauge.Set(m.Value) - - default: - return errors.E(op, errors.Errorf("collector `%s` does not support method Set", m.Name)) - } - - rpc.log.Info("set operation finished successfully", "name", m.Name, "labels", m.Labels, "value", m.Value) - - *ok = true - return nil -} |