Add stats counters to sinks

This commit is contained in:
Thomas Roehl 2022-04-02 16:06:03 +02:00
parent 4a4992877c
commit 5eeb097136
9 changed files with 92 additions and 26 deletions

View File

@ -11,6 +11,7 @@ import (
cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger" cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
stats "github.com/ClusterCockpit/cc-metric-collector/internal/metricRouter"
) )
const GMETRIC_EXEC = `gmetric` const GMETRIC_EXEC = `gmetric`
@ -32,6 +33,7 @@ type GangliaSink struct {
gmetric_path string gmetric_path string
gmetric_config string gmetric_config string
config GangliaSinkConfig config GangliaSinkConfig
statsSentMetrics int64
} }
func (s *GangliaSink) Write(point lp.CCMetric) error { func (s *GangliaSink) Write(point lp.CCMetric) error {
@ -78,6 +80,8 @@ func (s *GangliaSink) Write(point lp.CCMetric) error {
command := exec.Command(s.gmetric_path, argstr...) command := exec.Command(s.gmetric_path, argstr...)
command.Wait() command.Wait()
_, err = command.Output() _, err = command.Output()
s.statsSentMetrics++
stats.ComponentStatInt(s.name, "sent_metrics", s.statsSentMetrics)
return err return err
} }
@ -120,5 +124,6 @@ func NewGangliaSink(name string, config json.RawMessage) (Sink, error) {
if len(s.config.GmetricConfig) > 0 { if len(s.config.GmetricConfig) > 0 {
s.gmetric_config = s.config.GmetricConfig s.gmetric_config = s.config.GmetricConfig
} }
s.statsSentMetrics = 0
return s, nil return s, nil
} }

View File

@ -11,6 +11,7 @@ import (
cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger" cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
stats "github.com/ClusterCockpit/cc-metric-collector/internal/metricRouter"
influx "github.com/influxdata/line-protocol" influx "github.com/influxdata/line-protocol"
) )
@ -36,6 +37,8 @@ type HttpSink struct {
idleConnTimeout time.Duration idleConnTimeout time.Duration
timeout time.Duration timeout time.Duration
flushDelay time.Duration flushDelay time.Duration
statsProcessed int64
statsFlushes int64
} }
func (s *HttpSink) Write(m lp.CCMetric) error { func (s *HttpSink) Write(m lp.CCMetric) error {
@ -63,6 +66,8 @@ func (s *HttpSink) Write(m lp.CCMetric) error {
cclog.ComponentError(s.name, "encoding failed:", err.Error()) cclog.ComponentError(s.name, "encoding failed:", err.Error())
return err return err
} }
s.statsProcessed++
stats.ComponentStatInt(s.name, "processed_metrics", s.statsProcessed)
// Flush synchronously if "flush_delay" is zero // Flush synchronously if "flush_delay" is zero
if s.flushDelay == 0 { if s.flushDelay == 0 {
@ -112,6 +117,8 @@ func (s *HttpSink) Flush() error {
cclog.ComponentError(s.name, "application error:", err.Error()) cclog.ComponentError(s.name, "application error:", err.Error())
return err return err
} }
s.statsFlushes++
stats.ComponentStatInt(s.name, "flushes", s.statsFlushes)
return nil return nil
} }
@ -177,5 +184,7 @@ func NewHttpSink(name string, config json.RawMessage) (Sink, error) {
s.buffer = &bytes.Buffer{} s.buffer = &bytes.Buffer{}
s.encoder = influx.NewEncoder(s.buffer) s.encoder = influx.NewEncoder(s.buffer)
s.encoder.SetPrecision(time.Second) s.encoder.SetPrecision(time.Second)
s.statsFlushes = 0
s.statsProcessed = 0
return s, nil return s, nil
} }

View File

@ -10,6 +10,7 @@ import (
cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger" cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
stats "github.com/ClusterCockpit/cc-metric-collector/internal/metricRouter"
influxdb2 "github.com/influxdata/influxdb-client-go/v2" influxdb2 "github.com/influxdata/influxdb-client-go/v2"
influxdb2Api "github.com/influxdata/influxdb-client-go/v2/api" influxdb2Api "github.com/influxdata/influxdb-client-go/v2/api"
) )
@ -42,6 +43,9 @@ type InfluxAsyncSink struct {
config InfluxAsyncSinkConfig config InfluxAsyncSinkConfig
influxRetryInterval uint influxRetryInterval uint
influxMaxRetryTime uint influxMaxRetryTime uint
sentMetrics int64
statsFlushes int64
statsErrors int64
} }
func (s *InfluxAsyncSink) connect() error { func (s *InfluxAsyncSink) connect() error {
@ -105,11 +109,15 @@ func (s *InfluxAsyncSink) Write(m lp.CCMetric) error {
s.writeApi.WritePoint( s.writeApi.WritePoint(
m.ToPoint(s.meta_as_tags), m.ToPoint(s.meta_as_tags),
) )
s.sentMetrics++
stats.ComponentStatInt(s.name, "send_metrics", s.sentMetrics)
return nil return nil
} }
func (s *InfluxAsyncSink) Flush() error { func (s *InfluxAsyncSink) Flush() error {
s.writeApi.Flush() s.writeApi.Flush()
s.statsFlushes++
stats.ComponentStatInt(s.name, "flushes", s.statsFlushes)
return nil return nil
} }
@ -189,12 +197,17 @@ func NewInfluxAsyncSink(name string, config json.RawMessage) (Sink, error) {
} }
// Start background: Read from error channel // Start background: Read from error channel
s.statsErrors = 0
s.errors = s.writeApi.Errors() s.errors = s.writeApi.Errors()
go func() { go func() {
for err := range s.errors { for err := range s.errors {
s.statsErrors++
stats.ComponentStatInt(s.name, "errors", s.statsErrors)
cclog.ComponentError(s.name, err.Error()) cclog.ComponentError(s.name, err.Error())
} }
}() }()
s.sentMetrics = 0
s.statsFlushes = 0
return s, nil return s, nil
} }

View File

@ -11,6 +11,7 @@ import (
cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger" cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
stats "github.com/ClusterCockpit/cc-metric-collector/internal/metricRouter"
influxdb2 "github.com/influxdata/influxdb-client-go/v2" influxdb2 "github.com/influxdata/influxdb-client-go/v2"
influxdb2Api "github.com/influxdata/influxdb-client-go/v2/api" influxdb2Api "github.com/influxdata/influxdb-client-go/v2/api"
"github.com/influxdata/influxdb-client-go/v2/api/write" "github.com/influxdata/influxdb-client-go/v2/api/write"
@ -46,6 +47,8 @@ type InfluxSink struct {
flushTimer *time.Timer flushTimer *time.Timer
flushDelay time.Duration flushDelay time.Duration
lock sync.Mutex // Flush() runs in another goroutine, so this lock has to protect the buffer lock sync.Mutex // Flush() runs in another goroutine, so this lock has to protect the buffer
statsSentMetrics int64
statsProcessedMetrics int64
//influxMaxRetryDelay uint //influxMaxRetryDelay uint
} }
@ -123,8 +126,10 @@ func (s *InfluxSink) Write(m lp.CCMetric) error {
} }
p := m.ToPoint(s.meta_as_tags) p := m.ToPoint(s.meta_as_tags)
s.lock.Lock() s.lock.Lock()
s.statsProcessedMetrics++
s.batch = append(s.batch, p) s.batch = append(s.batch, p)
s.lock.Unlock() s.lock.Unlock()
stats.ComponentStatInt(s.name, "processed_metrics", s.statsProcessedMetrics)
// Flush synchronously if "flush_delay" is zero // Flush synchronously if "flush_delay" is zero
if s.flushDelay == 0 { if s.flushDelay == 0 {
@ -145,6 +150,8 @@ func (s *InfluxSink) Flush() error {
cclog.ComponentError(s.name, "flush failed:", err.Error()) cclog.ComponentError(s.name, "flush failed:", err.Error())
return err return err
} }
s.statsSentMetrics += int64(len(s.batch))
stats.ComponentStatInt(s.name, "sent_metrics", s.statsSentMetrics)
s.batch = s.batch[:0] s.batch = s.batch[:0]
return nil return nil
} }
@ -211,5 +218,7 @@ func NewInfluxSink(name string, config json.RawMessage) (Sink, error) {
if err := s.connect(); err != nil { if err := s.connect(); err != nil {
return nil, fmt.Errorf("unable to connect: %v", err) return nil, fmt.Errorf("unable to connect: %v", err)
} }
s.statsSentMetrics = 0
s.statsProcessedMetrics = 0
return s, nil return s, nil
} }

View File

@ -73,6 +73,7 @@ import (
cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger" cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
stats "github.com/ClusterCockpit/cc-metric-collector/internal/metricRouter"
"github.com/NVIDIA/go-nvml/pkg/dl" "github.com/NVIDIA/go-nvml/pkg/dl"
) )
@ -107,6 +108,7 @@ type LibgangliaSink struct {
gmond_config C.Ganglia_gmond_config gmond_config C.Ganglia_gmond_config
send_channels C.Ganglia_udp_send_channels send_channels C.Ganglia_udp_send_channels
cstrCache map[string]*C.char cstrCache map[string]*C.char
statsSentMetrics int64
} }
func (s *LibgangliaSink) Write(point lp.CCMetric) error { func (s *LibgangliaSink) Write(point lp.CCMetric) error {
@ -202,6 +204,8 @@ func (s *LibgangliaSink) Write(point lp.CCMetric) error {
C.Ganglia_metric_destroy(gmetric) C.Ganglia_metric_destroy(gmetric)
// Free the value C string, the only one not stored in the cache // Free the value C string, the only one not stored in the cache
C.free(unsafe.Pointer(c_value)) C.free(unsafe.Pointer(c_value))
s.statsSentMetrics++
stats.ComponentStatInt(s.name, "sent_metrics", s.statsSentMetrics)
return err return err
} }
@ -247,7 +251,7 @@ func NewLibgangliaSink(name string, config json.RawMessage) (Sink, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("error opening %s: %v", s.config.GangliaLib, err) return nil, fmt.Errorf("error opening %s: %v", s.config.GangliaLib, err)
} }
s.statsSentMetrics = 0
// Set up cache for the C strings // Set up cache for the C strings
s.cstrCache = make(map[string]*C.char) s.cstrCache = make(map[string]*C.char)
// s.cstrCache["globals"] = C.CString("globals") // s.cstrCache["globals"] = C.CString("globals")

View File

@ -11,6 +11,7 @@ import (
cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger" cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
stats "github.com/ClusterCockpit/cc-metric-collector/internal/metricRouter"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
@ -34,6 +35,7 @@ type PrometheusSink struct {
nodeMetrics map[string]prometheus.Gauge nodeMetrics map[string]prometheus.Gauge
promWg sync.WaitGroup promWg sync.WaitGroup
promServer *http.Server promServer *http.Server
statsSentMetrics int64
} }
func intToFloat64(input interface{}) (float64, error) { func intToFloat64(input interface{}) (float64, error) {
@ -113,6 +115,8 @@ func (s *PrometheusSink) newMetric(metric lp.CCMetric) error {
s.nodeMetrics[name] = new s.nodeMetrics[name] = new
prometheus.Register(new) prometheus.Register(new)
} }
s.statsSentMetrics++
stats.ComponentStatInt(s.name, "sent_metrics", s.statsSentMetrics)
return nil return nil
} }
@ -146,6 +150,8 @@ func (s *PrometheusSink) updateMetric(metric lp.CCMetric) error {
} }
s.nodeMetrics[name].Set(value) s.nodeMetrics[name].Set(value)
} }
s.statsSentMetrics++
stats.ComponentStatInt(s.name, "sent_metrics", s.statsSentMetrics)
return nil return nil
} }

View File

@ -7,6 +7,7 @@ import (
cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger" cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
stats "github.com/ClusterCockpit/cc-metric-collector/internal/metricRouter"
) )
type SampleSinkConfig struct { type SampleSinkConfig struct {
@ -14,12 +15,15 @@ type SampleSinkConfig struct {
// See: metricSink.go // See: metricSink.go
defaultSinkConfig defaultSinkConfig
// Additional config options, for SampleSink // Additional config options, for SampleSink
} }
type SampleSink struct { type SampleSink struct {
// declares elements 'name' and 'meta_as_tags' (string to bool map!) // declares elements 'name' and 'meta_as_tags' (string to bool map!)
sink sink
config SampleSinkConfig // entry point to the SampleSinkConfig config SampleSinkConfig // entry point to the SampleSinkConfig
// Stats counters
statsSentMetrics int64
} }
// Implement functions required for Sink interface // Implement functions required for Sink interface
@ -30,6 +34,8 @@ type SampleSink struct {
func (s *SampleSink) Write(point lp.CCMetric) error { func (s *SampleSink) Write(point lp.CCMetric) error {
// based on s.meta_as_tags use meta infos as tags // based on s.meta_as_tags use meta infos as tags
log.Print(point) log.Print(point)
s.statsSentMetrics++
stats.ComponentStatInt(s.name, "sent_metrics", s.statsSentMetrics)
return nil return nil
} }
@ -63,6 +69,9 @@ func NewSampleSink(name string, config json.RawMessage) (Sink, error) {
} }
} }
// Initalize stats counters
s.statsSentMetrics = 0
// Create lookup map to use meta infos as tags in the output metric // Create lookup map to use meta infos as tags in the output metric
s.meta_as_tags = make(map[string]bool) s.meta_as_tags = make(map[string]bool)
for _, k := range s.config.MetaAsTags { for _, k := range s.config.MetaAsTags {

View File

@ -102,13 +102,19 @@ func (sm *sinkManager) Start() {
} }
toTheSinks := func(p lp.CCMetric) { toTheSinks := func(p lp.CCMetric) {
var wg sync.WaitGroup
// Send received metric to all outputs // Send received metric to all outputs
cclog.ComponentDebug("SinkManager", "WRITE", p) cclog.ComponentDebug("SinkManager", "WRITE", p)
for _, s := range sm.sinks { for _, s := range sm.sinks {
wg.Add(1)
go func(s Sink) {
if err := s.Write(p); err != nil { if err := s.Write(p); err != nil {
cclog.ComponentError("SinkManager", "WRITE", s.Name(), "write failed:", err.Error()) cclog.ComponentError("SinkManager", "WRITE", s.Name(), "write failed:", err.Error())
} }
wg.Done()
}(s)
} }
wg.Wait()
} }
for { for {

View File

@ -8,6 +8,7 @@ import (
// "time" // "time"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
stats "github.com/ClusterCockpit/cc-metric-collector/internal/metricRouter"
) )
type StdoutSink struct { type StdoutSink struct {
@ -17,6 +18,7 @@ type StdoutSink struct {
defaultSinkConfig defaultSinkConfig
Output string `json:"output_file,omitempty"` Output string `json:"output_file,omitempty"`
} }
sentMetrics int64
} }
func (s *StdoutSink) Write(m lp.CCMetric) error { func (s *StdoutSink) Write(m lp.CCMetric) error {
@ -24,6 +26,8 @@ func (s *StdoutSink) Write(m lp.CCMetric) error {
s.output, s.output,
m.ToLineProtocol(s.meta_as_tags), m.ToLineProtocol(s.meta_as_tags),
) )
s.sentMetrics++
stats.ComponentStatInt(s.name, "sent_metrics", s.sentMetrics)
return nil return nil
} }
@ -68,6 +72,7 @@ func NewStdoutSink(name string, config json.RawMessage) (Sink, error) {
for _, k := range s.config.MetaAsTags { for _, k := range s.config.MetaAsTags {
s.meta_as_tags[k] = true s.meta_as_tags[k] = true
} }
s.sentMetrics = 0
return s, nil return s, nil
} }