package models import ( "fmt" "sync" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/metric" "github.com/influxdata/telegraf/selfstat" ) var ( AgentMetricsWritten = selfstat.Register("agent", "metrics_written", make(map[string]string)) AgentMetricsRejected = selfstat.Register("agent", "metrics_rejected", make(map[string]string)) AgentMetricsDropped = selfstat.Register("agent", "metrics_dropped", make(map[string]string)) registerGob = sync.OnceFunc(func() { metric.Init() }) ) type Transaction struct { // Batch of metrics to write Batch []telegraf.Metric // Accept denotes the indices of metrics that were successfully written Accept []int // Reject denotes the indices of metrics that were not written but should // not be requeued Reject []int // Marks this transaction as valid valid bool // Internal state that can be used by the buffer implementation state interface{} } func (tx *Transaction) AcceptAll() { tx.Accept = make([]int, len(tx.Batch)) for i := range tx.Batch { tx.Accept[i] = i } } func (*Transaction) KeepAll() {} func (tx *Transaction) InferKeep() []int { used := make([]bool, len(tx.Batch)) for _, idx := range tx.Accept { used[idx] = true } for _, idx := range tx.Reject { used[idx] = true } keep := make([]int, 0, len(tx.Batch)) for i := range tx.Batch { if !used[i] { keep = append(keep, i) } } return keep } type Buffer interface { // Len returns the number of metrics currently in the buffer. Len() int // Add adds metrics to the buffer and returns number of dropped metrics. Add(metrics ...telegraf.Metric) int // Batch starts a transaction by returning a slice of metrics up to the // given batch-size starting from the oldest metric in the buffer. Metrics // are ordered from oldest to newest and must not be modified by the plugin. BeginTransaction(batchSize int) *Transaction // Flush ends a metric and persists the buffer state EndTransaction(*Transaction) // Stats returns the buffer statistics such as rejected, dropped and accepted metrics Stats() BufferStats // Close finalizes the buffer and closes all open resources Close() error } // BufferStats holds common metrics used for buffer implementations. // Implementations of Buffer should embed this struct in them. type BufferStats struct { MetricsAdded selfstat.Stat MetricsWritten selfstat.Stat MetricsRejected selfstat.Stat MetricsDropped selfstat.Stat BufferSize selfstat.Stat BufferLimit selfstat.Stat } // NewBuffer returns a new empty Buffer with the given capacity. func NewBuffer(name, id, alias string, capacity int, strategy, path string) (Buffer, error) { registerGob() bs := NewBufferStats(name, alias, capacity) switch strategy { case "", "memory": return NewMemoryBuffer(capacity, bs) case "disk": return NewDiskBuffer(name, id, path, bs) } return nil, fmt.Errorf("invalid buffer strategy %q", strategy) } func NewBufferStats(name, alias string, capacity int) BufferStats { tags := map[string]string{"output": name} if alias != "" { tags["alias"] = alias } bs := BufferStats{ MetricsAdded: selfstat.Register( "write", "metrics_added", tags, ), MetricsWritten: selfstat.Register( "write", "metrics_written", tags, ), MetricsRejected: selfstat.Register( "write", "metrics_rejected", tags, ), MetricsDropped: selfstat.Register( "write", "metrics_dropped", tags, ), BufferSize: selfstat.Register( "write", "buffer_size", tags, ), BufferLimit: selfstat.Register( "write", "buffer_limit", tags, ), } bs.BufferSize.Set(int64(0)) bs.BufferLimit.Set(int64(capacity)) return bs } func (b *BufferStats) metricAdded() { b.MetricsAdded.Incr(1) } func (b *BufferStats) metricWritten(m telegraf.Metric) { AgentMetricsWritten.Incr(1) b.MetricsWritten.Incr(1) m.Accept() } func (b *BufferStats) metricRejected(m telegraf.Metric) { AgentMetricsRejected.Incr(1) b.MetricsRejected.Incr(1) m.Reject() } func (b *BufferStats) metricDropped(m telegraf.Metric) { AgentMetricsDropped.Incr(1) b.MetricsDropped.Incr(1) m.Reject() }