|
1 | 1 | package stats |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "os" |
5 | | - "path/filepath" |
6 | | - "reflect" |
7 | | - "sync" |
8 | 4 | "time" |
9 | | -) |
10 | | - |
11 | | -// An Engine carries the context for producing metrics, it is configured by |
12 | | -// setting the exported fields or using the helper methods to create sub-engines |
13 | | -// that inherit the configuration of the base they were created from. |
14 | | -// |
15 | | -// The program must not modify the engine's handler, prefix, or tags after it |
16 | | -// started using it. If changes need to be made new engines must be created by |
17 | | -// calls to WithPrefix or WithTags. |
18 | | -type Engine struct { |
19 | | - // The measure handler that the engine forwards measures to. |
20 | | - Handler Handler |
21 | | - |
22 | | - // A prefix set on all metric names produced by the engine. |
23 | | - Prefix string |
24 | | - |
25 | | - // A list of tags set on all metrics produced by the engine. |
26 | | - // |
27 | | - // The list of tags has to be sorted. This is automatically managed by the |
28 | | - // helper methods WithPrefix, WithTags and the NewEngine function. A program |
29 | | - // that manipulates this field directly has to respect this requirement. |
30 | | - Tags []Tag |
31 | 5 |
|
32 | | - // Indicates whether to allow duplicated tags from the tags list before sending. |
33 | | - // This option is turned off by default, ensuring that duplicate tags are removed. |
34 | | - // Turn it on if you need to send the same tag multiple times with different values, |
35 | | - // which is a special use case. |
36 | | - AllowDuplicateTags bool |
| 6 | + statsv5 "github.com/segmentio/stats/v5" |
| 7 | +) |
37 | 8 |
|
38 | | - // This cache keeps track of the generated measure structures to avoid |
39 | | - // rebuilding them every time a same measure type is seen by the engine. |
40 | | - // |
41 | | - // The cached values include the engine prefix in the measure names, which |
42 | | - // is why the cache must be local to the engine. |
43 | | - cache measureCache |
44 | | -} |
| 9 | +// Engine behaves like [stats/v5.Engine]. |
| 10 | +type Engine = statsv5.Engine |
45 | 11 |
|
46 | | -// NewEngine creates and returns a new engine configured with prefix, handler, |
47 | | -// and tags. |
| 12 | +// NewEngine behaves like [stats/v5.NewEngine]. |
48 | 13 | func NewEngine(prefix string, handler Handler, tags ...Tag) *Engine { |
49 | | - return &Engine{ |
50 | | - Handler: handler, |
51 | | - Prefix: prefix, |
52 | | - Tags: SortTags(copyTags(tags)), |
53 | | - } |
54 | | -} |
55 | | - |
56 | | -// Register adds handler to eng. |
57 | | -func (eng *Engine) Register(handler Handler) { |
58 | | - if eng.Handler == Discard { |
59 | | - eng.Handler = handler |
60 | | - } else { |
61 | | - eng.Handler = MultiHandler(eng.Handler, handler) |
62 | | - } |
63 | | -} |
64 | | - |
65 | | -// Flush flushes eng's handler (if it implements the Flusher interface). |
66 | | -func (eng *Engine) Flush() { |
67 | | - flush(eng.Handler) |
68 | | -} |
69 | | - |
70 | | -// WithPrefix returns a copy of the engine with prefix appended to eng's current |
71 | | -// prefix and tags set to the merge of eng's current tags and those passed as |
72 | | -// argument. Both eng and the returned engine share the same handler. |
73 | | -func (eng *Engine) WithPrefix(prefix string, tags ...Tag) *Engine { |
74 | | - return &Engine{ |
75 | | - Handler: eng.Handler, |
76 | | - Prefix: eng.makeName(prefix), |
77 | | - Tags: mergeTags(eng.Tags, tags), |
78 | | - } |
79 | | -} |
80 | | - |
81 | | -// WithTags returns a copy of the engine with tags set to the merge of eng's |
82 | | -// current tags and those passed as arguments. Both eng and the returned engine |
83 | | -// share the same handler. |
84 | | -func (eng *Engine) WithTags(tags ...Tag) *Engine { |
85 | | - return eng.WithPrefix("", tags...) |
86 | | -} |
87 | | - |
88 | | -// Incr increments by one the counter identified by name and tags. |
89 | | -func (eng *Engine) Incr(name string, tags ...Tag) { |
90 | | - eng.Add(name, 1, tags...) |
91 | | -} |
92 | | - |
93 | | -// IncrAt increments by one the counter identified by name and tags. |
94 | | -func (eng *Engine) IncrAt(time time.Time, name string, tags ...Tag) { |
95 | | - eng.AddAt(time, name, 1, tags...) |
96 | | -} |
97 | | - |
98 | | -// Add increments by value the counter identified by name and tags. |
99 | | -func (eng *Engine) Add(name string, value interface{}, tags ...Tag) { |
100 | | - eng.measure(time.Now(), name, value, Counter, tags...) |
101 | | -} |
102 | | - |
103 | | -// AddAt increments by value the counter identified by name and tags. |
104 | | -func (eng *Engine) AddAt(t time.Time, name string, value interface{}, tags ...Tag) { |
105 | | - eng.measure(t, name, value, Counter, tags...) |
106 | | -} |
107 | | - |
108 | | -// Set sets to value the gauge identified by name and tags. |
109 | | -func (eng *Engine) Set(name string, value interface{}, tags ...Tag) { |
110 | | - eng.measure(time.Now(), name, value, Gauge, tags...) |
111 | | -} |
112 | | - |
113 | | -// SetAt sets to value the gauge identified by name and tags. |
114 | | -func (eng *Engine) SetAt(t time.Time, name string, value interface{}, tags ...Tag) { |
115 | | - eng.measure(t, name, value, Gauge, tags...) |
116 | | -} |
117 | | - |
118 | | -// Observe reports value for the histogram identified by name and tags. |
119 | | -func (eng *Engine) Observe(name string, value interface{}, tags ...Tag) { |
120 | | - eng.measure(time.Now(), name, value, Histogram, tags...) |
121 | | -} |
122 | | - |
123 | | -// ObserveAt reports value for the histogram identified by name and tags. |
124 | | -func (eng *Engine) ObserveAt(t time.Time, name string, value interface{}, tags ...Tag) { |
125 | | - eng.measure(t, name, value, Histogram, tags...) |
126 | | -} |
127 | | - |
128 | | -// Clock returns a new clock identified by name and tags. |
129 | | -func (eng *Engine) Clock(name string, tags ...Tag) *Clock { |
130 | | - return eng.ClockAt(name, time.Now(), tags...) |
131 | | -} |
132 | | - |
133 | | -// ClockAt returns a new clock identified by name and tags with a specified |
134 | | -// start time. |
135 | | -func (eng *Engine) ClockAt(name string, start time.Time, tags ...Tag) *Clock { |
136 | | - cpy := make([]Tag, len(tags), len(tags)+1) // clock always appends a stamp. |
137 | | - copy(cpy, tags) |
138 | | - return &Clock{ |
139 | | - name: name, |
140 | | - first: start, |
141 | | - last: start, |
142 | | - tags: cpy, |
143 | | - eng: eng, |
144 | | - } |
| 14 | + return statsv5.NewEngine(prefix, handler, tags...) |
145 | 15 | } |
146 | 16 |
|
147 | | -func (eng *Engine) measure(t time.Time, name string, value interface{}, ftype FieldType, tags ...Tag) { |
148 | | - name, field := splitMeasureField(name) |
149 | | - mp := measureArrayPool.Get().(*[1]Measure) |
150 | | - |
151 | | - m := &(*mp)[0] |
152 | | - m.Name = eng.makeName(name) // TODO: figure out how to optimize this |
153 | | - m.Fields = append(m.Fields[:0], MakeField(field, value, ftype)) |
154 | | - m.Tags = append(m.Tags[:0], eng.Tags...) |
155 | | - m.Tags = append(m.Tags, tags...) |
156 | | - |
157 | | - if len(tags) != 0 && !eng.AllowDuplicateTags && !TagsAreSorted(m.Tags) { |
158 | | - SortTags(m.Tags) |
159 | | - } |
160 | | - |
161 | | - eng.Handler.HandleMeasures(t, (*mp)[:]...) |
| 17 | +// DefaultEngine behaves like [stats/v5.DefaultEngine]. |
| 18 | +var DefaultEngine = statsv5.DefaultEngine |
162 | 19 |
|
163 | | - for i := range m.Fields { |
164 | | - m.Fields[i] = Field{} |
165 | | - } |
166 | | - |
167 | | - for i := range m.Tags { |
168 | | - m.Tags[i] = Tag{} |
169 | | - } |
170 | | - |
171 | | - m.Name = "" |
172 | | - measureArrayPool.Put(mp) |
173 | | -} |
174 | | - |
175 | | -func (eng *Engine) makeName(name string) string { |
176 | | - return concat(eng.Prefix, name) |
177 | | -} |
178 | | - |
179 | | -var measureArrayPool = sync.Pool{ |
180 | | - New: func() interface{} { return new([1]Measure) }, |
181 | | -} |
182 | | - |
183 | | -// Report calls ReportAt with time.Now() as first argument. |
184 | | -func (eng *Engine) Report(metrics interface{}, tags ...Tag) { |
185 | | - eng.ReportAt(time.Now(), metrics, tags...) |
186 | | -} |
187 | | - |
188 | | -// ReportAt reports a set of metrics for a given time. The metrics must be of |
189 | | -// type struct, pointer to struct, or a slice or array to one of those. See |
190 | | -// MakeMeasures for details about how to make struct types exposing metrics. |
191 | | -func (eng *Engine) ReportAt(time time.Time, metrics interface{}, tags ...Tag) { |
192 | | - var tb *tagsBuffer |
193 | | - |
194 | | - if len(tags) == 0 { |
195 | | - // fast path for the common case where there are no dynamic tags |
196 | | - tags = eng.Tags |
197 | | - } else { |
198 | | - tb = tagsPool.Get().(*tagsBuffer) |
199 | | - tb.append(tags...) |
200 | | - tb.append(eng.Tags...) |
201 | | - if !eng.AllowDuplicateTags { |
202 | | - tb.sort() |
203 | | - } |
204 | | - tags = tb.tags |
205 | | - } |
206 | | - |
207 | | - mb := measurePool.Get().(*measuresBuffer) |
208 | | - mb.measures = appendMeasures(mb.measures[:0], &eng.cache, eng.Prefix, reflect.ValueOf(metrics), tags...) |
209 | | - |
210 | | - ms := mb.measures |
211 | | - eng.Handler.HandleMeasures(time, ms...) |
212 | | - |
213 | | - for i := range ms { |
214 | | - ms[i].reset() |
215 | | - } |
216 | | - |
217 | | - if tb != nil { |
218 | | - tb.reset() |
219 | | - tagsPool.Put(tb) |
220 | | - } |
221 | | - |
222 | | - measurePool.Put(mb) |
223 | | -} |
224 | | - |
225 | | -// DefaultEngine is the engine used by global helper functions. |
226 | | -var DefaultEngine = NewEngine(progname(), Discard) |
227 | | - |
228 | | -// Register adds handler to the default engine. |
| 20 | +// Register behaves like [stats/v5.Register]. |
229 | 21 | func Register(handler Handler) { |
230 | | - DefaultEngine.Register(handler) |
| 22 | + statsv5.Register(handler) |
231 | 23 | } |
232 | 24 |
|
233 | | -// Flush flushes the default engine. |
| 25 | +// Flush behaves like [stats/v5.Flush]. |
234 | 26 | func Flush() { |
235 | | - DefaultEngine.Flush() |
| 27 | + statsv5.Flush() |
236 | 28 | } |
237 | 29 |
|
238 | | -// WithPrefix returns a copy of the engine with prefix appended to default |
239 | | -// engine's current prefix and tags set to the merge of eng's current tags and |
240 | | -// those passed as argument. Both the default engine and the returned engine |
241 | | -// share the same handler. |
| 30 | +// WithPrefix behaves like [stats/v5.WithPrefix]. |
242 | 31 | func WithPrefix(prefix string, tags ...Tag) *Engine { |
243 | | - return DefaultEngine.WithPrefix(prefix, tags...) |
| 32 | + return statsv5.WithPrefix(prefix, tags...) |
244 | 33 | } |
245 | 34 |
|
246 | | -// WithTags returns a copy of the engine with tags set to the merge of the |
247 | | -// default engine's current tags and those passed as arguments. Both the default |
248 | | -// engine and the returned engine share the same handler. |
| 35 | +// WithTags behaves like [stats/v5.WithTags]. |
249 | 36 | func WithTags(tags ...Tag) *Engine { |
250 | | - return DefaultEngine.WithTags(tags...) |
| 37 | + return statsv5.WithTags(tags...) |
251 | 38 | } |
252 | 39 |
|
253 | | -// Incr increments by one the counter identified by name and tags. |
| 40 | +// Incr behaves like [stats/v5.Incr]. |
254 | 41 | func Incr(name string, tags ...Tag) { |
255 | | - DefaultEngine.Incr(name, tags...) |
| 42 | + statsv5.Incr(name, tags...) |
256 | 43 | } |
257 | 44 |
|
258 | | -// IncrAt increments by one the counter identified by name and tags. |
| 45 | +// IncrAt behaves like [stats/v5.IncrAt]. |
259 | 46 | func IncrAt(time time.Time, name string, tags ...Tag) { |
260 | | - DefaultEngine.IncrAt(time, name, tags...) |
| 47 | + statsv5.IncrAt(time, name, tags...) |
261 | 48 | } |
262 | 49 |
|
263 | | -// Add increments by value the counter identified by name and tags. |
| 50 | +// Add behaves like [stats/v5.Add]. |
264 | 51 | func Add(name string, value interface{}, tags ...Tag) { |
265 | | - DefaultEngine.Add(name, value, tags...) |
| 52 | + statsv5.Add(name, value, tags...) |
266 | 53 | } |
267 | 54 |
|
268 | | -// AddAt increments by value the counter identified by name and tags. |
| 55 | +// AddAt behaves like [stats/v5.AddAt]. |
269 | 56 | func AddAt(time time.Time, name string, value interface{}, tags ...Tag) { |
270 | | - DefaultEngine.AddAt(time, name, value, tags...) |
| 57 | + statsv5.AddAt(time, name, value, tags...) |
271 | 58 | } |
272 | 59 |
|
273 | | -// Set sets to value the gauge identified by name and tags. |
| 60 | +// Set behaves like [stats/v5.Set]. |
274 | 61 | func Set(name string, value interface{}, tags ...Tag) { |
275 | | - DefaultEngine.Set(name, value, tags...) |
| 62 | + statsv5.Set(name, value, tags...) |
276 | 63 | } |
277 | 64 |
|
278 | | -// SetAt sets to value the gauge identified by name and tags. |
| 65 | +// SetAt behaves like [stats/v5.SetAt]. |
279 | 66 | func SetAt(time time.Time, name string, value interface{}, tags ...Tag) { |
280 | | - DefaultEngine.SetAt(time, name, value, tags...) |
| 67 | + statsv5.SetAt(time, name, value, tags...) |
281 | 68 | } |
282 | 69 |
|
283 | | -// Observe reports value for the histogram identified by name and tags. |
| 70 | +// Observe behaves like [stats/v5.Observe]. |
284 | 71 | func Observe(name string, value interface{}, tags ...Tag) { |
285 | | - DefaultEngine.Observe(name, value, tags...) |
| 72 | + statsv5.Observe(name, value, tags...) |
286 | 73 | } |
287 | 74 |
|
288 | | -// ObserveAt reports value for the histogram identified by name and tags. |
| 75 | +// ObserveAt behaves like [stats/v5.ObserveAt]. |
289 | 76 | func ObserveAt(time time.Time, name string, value interface{}, tags ...Tag) { |
290 | | - DefaultEngine.ObserveAt(time, name, value, tags...) |
| 77 | + statsv5.ObserveAt(time, name, value, tags...) |
291 | 78 | } |
292 | 79 |
|
293 | | -// Report is a helper function that delegates to DefaultEngine. |
| 80 | +// Report behaves like [stats/v5.Report]. |
294 | 81 | func Report(metrics interface{}, tags ...Tag) { |
295 | | - DefaultEngine.Report(metrics, tags...) |
| 82 | + statsv5.Report(metrics, tags...) |
296 | 83 | } |
297 | 84 |
|
298 | | -// ReportAt is a helper function that delegates to DefaultEngine. |
| 85 | +// ReportAt behaves like [stats/v5.ReportAt]. |
299 | 86 | func ReportAt(time time.Time, metrics interface{}, tags ...Tag) { |
300 | | - DefaultEngine.ReportAt(time, metrics, tags...) |
301 | | -} |
302 | | - |
303 | | -func progname() (name string) { |
304 | | - if args := os.Args; len(args) != 0 { |
305 | | - name = filepath.Base(args[0]) |
306 | | - } |
307 | | - return |
| 87 | + statsv5.ReportAt(time, metrics, tags...) |
308 | 88 | } |
0 commit comments