Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/component/loki/process/internal/metric/counters.go
4096 views
1
package metric
2
3
import (
4
"fmt"
5
"time"
6
7
"github.com/prometheus/client_golang/prometheus"
8
"github.com/prometheus/common/model"
9
)
10
11
const (
12
CounterInc = "inc"
13
CounterAdd = "add"
14
)
15
16
// CounterConfig defines a counter metric whose value only goes up.
17
type CounterConfig struct {
18
// Shared fields
19
Name string `river:"name,attr"`
20
Description string `river:"description,attr,optional"`
21
Source string `river:"source,attr,optional"`
22
Prefix string `river:"prefix,attr,optional"`
23
MaxIdle time.Duration `river:"max_idle_duration,attr,optional"`
24
Value string `river:"value,attr,optional"`
25
26
// Counter-specific fields
27
Action string `river:"action,attr"`
28
MatchAll bool `river:"match_all,attr,optional"`
29
CountEntryBytes bool `river:"count_entry_bytes,attr,optional"`
30
}
31
32
// DefaultCounterConfig sets the default for a Counter.
33
var DefaultCounterConfig = CounterConfig{
34
MaxIdle: 5 * time.Minute,
35
}
36
37
// UnmarshalRiver implements the unmarshaller
38
func (c *CounterConfig) UnmarshalRiver(f func(v interface{}) error) error {
39
*c = DefaultCounterConfig
40
type counter CounterConfig
41
err := f((*counter)(c))
42
if err != nil {
43
return err
44
}
45
46
if c.MaxIdle < 1*time.Second {
47
return fmt.Errorf("max_idle_duration must be greater or equal than 1s")
48
}
49
50
if c.Source == "" {
51
c.Source = c.Name
52
}
53
if c.Action != CounterInc && c.Action != CounterAdd {
54
return fmt.Errorf("the 'action' counter field must be either 'inc' or 'add'")
55
}
56
57
if c.MatchAll && c.Value != "" {
58
return fmt.Errorf("a 'counter' metric supports either 'match_all' or a 'value', but not both")
59
}
60
if c.CountEntryBytes && (!c.MatchAll && c.Action != "add") {
61
return fmt.Errorf("the 'count_entry_bytes' counter field must be specified along with match_all set to true or action set to 'add'")
62
}
63
return nil
64
}
65
66
// Counters is a vector of counters for a log stream.
67
type Counters struct {
68
*metricVec
69
Cfg *CounterConfig
70
}
71
72
// NewCounters creates a new counter vec.
73
func NewCounters(name string, config *CounterConfig) (*Counters, error) {
74
return &Counters{
75
metricVec: newMetricVec(func(labels map[string]string) prometheus.Metric {
76
return &expiringCounter{prometheus.NewCounter(prometheus.CounterOpts{
77
Help: config.Description,
78
Name: name,
79
ConstLabels: labels,
80
}),
81
0,
82
}
83
}, int64(config.MaxIdle.Seconds())),
84
Cfg: config,
85
}, nil
86
}
87
88
// With returns the counter associated with a stream labelset.
89
func (c *Counters) With(labels model.LabelSet) prometheus.Counter {
90
return c.metricVec.With(labels).(prometheus.Counter)
91
}
92
93
type expiringCounter struct {
94
prometheus.Counter
95
lastModSec int64
96
}
97
98
// Inc increments the counter by 1. Use Add to increment it by arbitrary
99
// non-negative values.
100
func (e *expiringCounter) Inc() {
101
e.Counter.Inc()
102
e.lastModSec = time.Now().Unix()
103
}
104
105
// Add adds the given value to the counter. It panics if the value is <
106
// 0.
107
func (e *expiringCounter) Add(val float64) {
108
e.Counter.Add(val)
109
e.lastModSec = time.Now().Unix()
110
}
111
112
// HasExpired implements Expirable
113
func (e *expiringCounter) HasExpired(currentTimeSec int64, maxAgeSec int64) bool {
114
return currentTimeSec-e.lastModSec >= maxAgeSec
115
}
116
117