master
go 152 lines 4.03 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package metrix
4
5 // snapshotCounterInstrument writes sampled monotonic totals.
6 type snapshotCounterInstrument struct {
7 backend meterBackend
8 desc *instrumentDescriptor
9 scope HostScope
10 base []LabelSet
11 }
12
13 // statefulCounterInstrument writes maintained counter deltas.
14 type statefulCounterInstrument struct {
15 backend meterBackend
16 desc *instrumentDescriptor
17 scope HostScope
18 base []LabelSet
19 }
20
21 // stagedCounter holds one in-cycle counter current total for a series identity.
22 type stagedCounter struct {
23 key string
24 name string
25 hostScopeKey string
26 hostScope HostScope
27 labels []Label
28 labelsKey string
29 desc *instrumentDescriptor
30 current SampleValue
31 }
32
33 // Counter declares or reuses a snapshot counter under this meter.
34 func (m *snapshotMeter) Counter(name string, opts ...InstrumentOption) SnapshotCounter {
35 desc, err := m.backend.registerInstrument(metricName(m.prefix, name), kindCounter, modeSnapshot, opts...)
36 if err != nil {
37 panic(err)
38 }
39 return &snapshotCounterInstrument{
40 backend: m.backend,
41 desc: desc,
42 scope: m.scope,
43 base: appendLabelSets(m.sets, nil),
44 }
45 }
46
47 // Counter declares or reuses a stateful counter under this meter.
48 func (m *statefulMeter) Counter(name string, opts ...InstrumentOption) StatefulCounter {
49 desc, err := m.backend.registerInstrument(metricName(m.prefix, name), kindCounter, modeStateful, opts...)
50 if err != nil {
51 panic(err)
52 }
53 return &statefulCounterInstrument{
54 backend: m.backend,
55 desc: desc,
56 scope: m.scope,
57 base: appendLabelSets(m.sets, nil),
58 }
59 }
60
61 // ObserveTotal writes one monotonic total sample for this collect cycle.
62 func (c *snapshotCounterInstrument) ObserveTotal(v SampleValue, labels ...LabelSet) {
63 c.backend.recordCounterObserveTotal(c.desc, c.scope, v, appendLabelSets(c.base, labels))
64 }
65
66 // Add accumulates a delta for this collect cycle.
67 func (c *statefulCounterInstrument) Add(delta SampleValue, labels ...LabelSet) {
68 c.backend.recordCounterAdd(c.desc, c.scope, delta, appendLabelSets(c.base, labels))
69 }
70
71 // recordCounterObserveTotal writes one sampled monotonic total for snapshot counters.
72 func (c *storeCore) recordCounterObserveTotal(desc *instrumentDescriptor, scope HostScope, value SampleValue, sets []LabelSet) {
73 mustFiniteSample(value)
74
75 c.mu.Lock()
76 defer c.mu.Unlock()
77
78 if c.active == nil {
79 panic(errCycleInactive)
80 }
81
82 labels, labelsKey, err := labelsFromSet(sets, c)
83 if err != nil {
84 panic(err)
85 }
86 scope, ok := c.prepareHostScopeForWriteLocked(scope)
87 if !ok {
88 return
89 }
90
91 key := makeSeriesKey(scope.ScopeKey, desc.name, labelsKey)
92 entry, ok := c.active.counters[key]
93 if !ok {
94 entry = &stagedCounter{
95 key: key,
96 name: desc.name,
97 hostScopeKey: scope.ScopeKey,
98 hostScope: scope,
99 labels: labels,
100 labelsKey: labelsKey,
101 desc: desc,
102 }
103 c.active.counters[key] = entry
104 }
105 entry.current = value // last-write-wins in-cycle
106 }
107
108 // recordCounterAdd accumulates delta for stateful counters.
109 func (c *storeCore) recordCounterAdd(desc *instrumentDescriptor, scope HostScope, delta SampleValue, sets []LabelSet) {
110 mustFiniteSample(delta)
111
112 if delta < 0 {
113 panic(errCounterNegativeDelta)
114 }
115
116 c.mu.Lock()
117 defer c.mu.Unlock()
118
119 if c.active == nil {
120 panic(errCycleInactive)
121 }
122
123 labels, labelsKey, err := labelsFromSet(sets, c)
124 if err != nil {
125 panic(err)
126 }
127 scope, ok := c.prepareHostScopeForWriteLocked(scope)
128 if !ok {
129 return
130 }
131
132 key := makeSeriesKey(scope.ScopeKey, desc.name, labelsKey)
133 entry, ok := c.active.counters[key]
134 if !ok {
135 baseline := SampleValue(0)
136 if existing := c.snapshot.Load().series[key]; existing != nil && existing.desc != nil && existing.desc.kind == kindCounter {
137 baseline = existing.counterCurrent
138 }
139 entry = &stagedCounter{
140 key: key,
141 name: desc.name,
142 hostScopeKey: scope.ScopeKey,
143 hostScope: scope,
144 labels: labels,
145 labelsKey: labelsKey,
146 desc: desc,
147 current: baseline,
148 }
149 c.active.counters[key] = entry
150 }
151 entry.current += delta
152 }