instrument.go raw
1 // Copyright The OpenTelemetry Authors
2 // SPDX-License-Identifier: Apache-2.0
3
4 package metric // import "go.opentelemetry.io/otel/metric"
5
6 import "go.opentelemetry.io/otel/attribute"
7
8 // Observable is used as a grouping mechanism for all instruments that are
9 // updated within a Callback.
10 type Observable interface {
11 observable()
12 }
13
14 // InstrumentOption applies options to all instruments.
15 type InstrumentOption interface {
16 Int64CounterOption
17 Int64UpDownCounterOption
18 Int64HistogramOption
19 Int64GaugeOption
20 Int64ObservableCounterOption
21 Int64ObservableUpDownCounterOption
22 Int64ObservableGaugeOption
23
24 Float64CounterOption
25 Float64UpDownCounterOption
26 Float64HistogramOption
27 Float64GaugeOption
28 Float64ObservableCounterOption
29 Float64ObservableUpDownCounterOption
30 Float64ObservableGaugeOption
31 }
32
33 // HistogramOption applies options to histogram instruments.
34 type HistogramOption interface {
35 Int64HistogramOption
36 Float64HistogramOption
37 }
38
39 type descOpt string
40
41 func (o descOpt) applyFloat64Counter(c Float64CounterConfig) Float64CounterConfig {
42 c.description = string(o)
43 return c
44 }
45
46 func (o descOpt) applyFloat64UpDownCounter(c Float64UpDownCounterConfig) Float64UpDownCounterConfig {
47 c.description = string(o)
48 return c
49 }
50
51 func (o descOpt) applyFloat64Histogram(c Float64HistogramConfig) Float64HistogramConfig {
52 c.description = string(o)
53 return c
54 }
55
56 func (o descOpt) applyFloat64Gauge(c Float64GaugeConfig) Float64GaugeConfig {
57 c.description = string(o)
58 return c
59 }
60
61 func (o descOpt) applyFloat64ObservableCounter(c Float64ObservableCounterConfig) Float64ObservableCounterConfig {
62 c.description = string(o)
63 return c
64 }
65
66 func (o descOpt) applyFloat64ObservableUpDownCounter(
67 c Float64ObservableUpDownCounterConfig,
68 ) Float64ObservableUpDownCounterConfig {
69 c.description = string(o)
70 return c
71 }
72
73 func (o descOpt) applyFloat64ObservableGauge(c Float64ObservableGaugeConfig) Float64ObservableGaugeConfig {
74 c.description = string(o)
75 return c
76 }
77
78 func (o descOpt) applyInt64Counter(c Int64CounterConfig) Int64CounterConfig {
79 c.description = string(o)
80 return c
81 }
82
83 func (o descOpt) applyInt64UpDownCounter(c Int64UpDownCounterConfig) Int64UpDownCounterConfig {
84 c.description = string(o)
85 return c
86 }
87
88 func (o descOpt) applyInt64Histogram(c Int64HistogramConfig) Int64HistogramConfig {
89 c.description = string(o)
90 return c
91 }
92
93 func (o descOpt) applyInt64Gauge(c Int64GaugeConfig) Int64GaugeConfig {
94 c.description = string(o)
95 return c
96 }
97
98 func (o descOpt) applyInt64ObservableCounter(c Int64ObservableCounterConfig) Int64ObservableCounterConfig {
99 c.description = string(o)
100 return c
101 }
102
103 func (o descOpt) applyInt64ObservableUpDownCounter(
104 c Int64ObservableUpDownCounterConfig,
105 ) Int64ObservableUpDownCounterConfig {
106 c.description = string(o)
107 return c
108 }
109
110 func (o descOpt) applyInt64ObservableGauge(c Int64ObservableGaugeConfig) Int64ObservableGaugeConfig {
111 c.description = string(o)
112 return c
113 }
114
115 // WithDescription sets the instrument description.
116 func WithDescription(desc string) InstrumentOption { return descOpt(desc) }
117
118 type unitOpt string
119
120 func (o unitOpt) applyFloat64Counter(c Float64CounterConfig) Float64CounterConfig {
121 c.unit = string(o)
122 return c
123 }
124
125 func (o unitOpt) applyFloat64UpDownCounter(c Float64UpDownCounterConfig) Float64UpDownCounterConfig {
126 c.unit = string(o)
127 return c
128 }
129
130 func (o unitOpt) applyFloat64Histogram(c Float64HistogramConfig) Float64HistogramConfig {
131 c.unit = string(o)
132 return c
133 }
134
135 func (o unitOpt) applyFloat64Gauge(c Float64GaugeConfig) Float64GaugeConfig {
136 c.unit = string(o)
137 return c
138 }
139
140 func (o unitOpt) applyFloat64ObservableCounter(c Float64ObservableCounterConfig) Float64ObservableCounterConfig {
141 c.unit = string(o)
142 return c
143 }
144
145 func (o unitOpt) applyFloat64ObservableUpDownCounter(
146 c Float64ObservableUpDownCounterConfig,
147 ) Float64ObservableUpDownCounterConfig {
148 c.unit = string(o)
149 return c
150 }
151
152 func (o unitOpt) applyFloat64ObservableGauge(c Float64ObservableGaugeConfig) Float64ObservableGaugeConfig {
153 c.unit = string(o)
154 return c
155 }
156
157 func (o unitOpt) applyInt64Counter(c Int64CounterConfig) Int64CounterConfig {
158 c.unit = string(o)
159 return c
160 }
161
162 func (o unitOpt) applyInt64UpDownCounter(c Int64UpDownCounterConfig) Int64UpDownCounterConfig {
163 c.unit = string(o)
164 return c
165 }
166
167 func (o unitOpt) applyInt64Histogram(c Int64HistogramConfig) Int64HistogramConfig {
168 c.unit = string(o)
169 return c
170 }
171
172 func (o unitOpt) applyInt64Gauge(c Int64GaugeConfig) Int64GaugeConfig {
173 c.unit = string(o)
174 return c
175 }
176
177 func (o unitOpt) applyInt64ObservableCounter(c Int64ObservableCounterConfig) Int64ObservableCounterConfig {
178 c.unit = string(o)
179 return c
180 }
181
182 func (o unitOpt) applyInt64ObservableUpDownCounter(
183 c Int64ObservableUpDownCounterConfig,
184 ) Int64ObservableUpDownCounterConfig {
185 c.unit = string(o)
186 return c
187 }
188
189 func (o unitOpt) applyInt64ObservableGauge(c Int64ObservableGaugeConfig) Int64ObservableGaugeConfig {
190 c.unit = string(o)
191 return c
192 }
193
194 // WithUnit sets the instrument unit.
195 //
196 // The unit u should be defined using the appropriate [UCUM](https://ucum.org) case-sensitive code.
197 func WithUnit(u string) InstrumentOption { return unitOpt(u) }
198
199 // WithExplicitBucketBoundaries sets the instrument explicit bucket boundaries.
200 //
201 // This option is considered "advisory", and may be ignored by API implementations.
202 func WithExplicitBucketBoundaries(bounds ...float64) HistogramOption { return bucketOpt(bounds) }
203
204 type bucketOpt []float64
205
206 func (o bucketOpt) applyFloat64Histogram(c Float64HistogramConfig) Float64HistogramConfig {
207 c.explicitBucketBoundaries = o
208 return c
209 }
210
211 func (o bucketOpt) applyInt64Histogram(c Int64HistogramConfig) Int64HistogramConfig {
212 c.explicitBucketBoundaries = o
213 return c
214 }
215
216 // AddOption applies options to an addition measurement. See
217 // [MeasurementOption] for other options that can be used as an AddOption.
218 type AddOption interface {
219 applyAdd(AddConfig) AddConfig
220 }
221
222 // AddConfig contains options for an addition measurement.
223 type AddConfig struct {
224 attrs attribute.Set
225 }
226
227 // NewAddConfig returns a new [AddConfig] with all opts applied.
228 func NewAddConfig(opts []AddOption) AddConfig {
229 config := AddConfig{attrs: *attribute.EmptySet()}
230 for _, o := range opts {
231 config = o.applyAdd(config)
232 }
233 return config
234 }
235
236 // Attributes returns the configured attribute set.
237 func (c AddConfig) Attributes() attribute.Set {
238 return c.attrs
239 }
240
241 // RecordOption applies options to an addition measurement. See
242 // [MeasurementOption] for other options that can be used as a RecordOption.
243 type RecordOption interface {
244 applyRecord(RecordConfig) RecordConfig
245 }
246
247 // RecordConfig contains options for a recorded measurement.
248 type RecordConfig struct {
249 attrs attribute.Set
250 }
251
252 // NewRecordConfig returns a new [RecordConfig] with all opts applied.
253 func NewRecordConfig(opts []RecordOption) RecordConfig {
254 config := RecordConfig{attrs: *attribute.EmptySet()}
255 for _, o := range opts {
256 config = o.applyRecord(config)
257 }
258 return config
259 }
260
261 // Attributes returns the configured attribute set.
262 func (c RecordConfig) Attributes() attribute.Set {
263 return c.attrs
264 }
265
266 // ObserveOption applies options to an addition measurement. See
267 // [MeasurementOption] for other options that can be used as a ObserveOption.
268 type ObserveOption interface {
269 applyObserve(ObserveConfig) ObserveConfig
270 }
271
272 // ObserveConfig contains options for an observed measurement.
273 type ObserveConfig struct {
274 attrs attribute.Set
275 }
276
277 // NewObserveConfig returns a new [ObserveConfig] with all opts applied.
278 func NewObserveConfig(opts []ObserveOption) ObserveConfig {
279 config := ObserveConfig{attrs: *attribute.EmptySet()}
280 for _, o := range opts {
281 config = o.applyObserve(config)
282 }
283 return config
284 }
285
286 // Attributes returns the configured attribute set.
287 func (c ObserveConfig) Attributes() attribute.Set {
288 return c.attrs
289 }
290
291 // MeasurementOption applies options to all instrument measurement.
292 type MeasurementOption interface {
293 AddOption
294 RecordOption
295 ObserveOption
296 }
297
298 type attrOpt struct {
299 set attribute.Set
300 }
301
302 // mergeSets returns the union of keys between a and b. Any duplicate keys will
303 // use the value associated with b.
304 func mergeSets(a, b attribute.Set) attribute.Set {
305 // NewMergeIterator uses the first value for any duplicates.
306 iter := attribute.NewMergeIterator(&b, &a)
307 merged := make([]attribute.KeyValue, 0, a.Len()+b.Len())
308 for iter.Next() {
309 merged = append(merged, iter.Attribute())
310 }
311 return attribute.NewSet(merged...)
312 }
313
314 func (o attrOpt) applyAdd(c AddConfig) AddConfig {
315 switch {
316 case o.set.Len() == 0:
317 case c.attrs.Len() == 0:
318 c.attrs = o.set
319 default:
320 c.attrs = mergeSets(c.attrs, o.set)
321 }
322 return c
323 }
324
325 func (o attrOpt) applyRecord(c RecordConfig) RecordConfig {
326 switch {
327 case o.set.Len() == 0:
328 case c.attrs.Len() == 0:
329 c.attrs = o.set
330 default:
331 c.attrs = mergeSets(c.attrs, o.set)
332 }
333 return c
334 }
335
336 func (o attrOpt) applyObserve(c ObserveConfig) ObserveConfig {
337 switch {
338 case o.set.Len() == 0:
339 case c.attrs.Len() == 0:
340 c.attrs = o.set
341 default:
342 c.attrs = mergeSets(c.attrs, o.set)
343 }
344 return c
345 }
346
347 // WithAttributeSet sets the attribute Set associated with a measurement is
348 // made with.
349 //
350 // If multiple WithAttributeSet or WithAttributes options are passed the
351 // attributes will be merged together in the order they are passed. Attributes
352 // with duplicate keys will use the last value passed.
353 func WithAttributeSet(attributes attribute.Set) MeasurementOption {
354 return attrOpt{set: attributes}
355 }
356
357 // WithAttributes converts attributes into an attribute Set and sets the Set to
358 // be associated with a measurement. This is shorthand for:
359 //
360 // cp := make([]attribute.KeyValue, len(attributes))
361 // copy(cp, attributes)
362 // WithAttributeSet(attribute.NewSet(cp...))
363 //
364 // [attribute.NewSet] may modify the passed attributes so this will make a copy
365 // of attributes before creating a set in order to ensure this function is
366 // concurrent safe. This makes this option function less optimized in
367 // comparison to [WithAttributeSet]. Therefore, [WithAttributeSet] should be
368 // preferred for performance sensitive code.
369 //
370 // See [WithAttributeSet] for information about how multiple WithAttributes are
371 // merged.
372 func WithAttributes(attributes ...attribute.KeyValue) MeasurementOption {
373 cp := make([]attribute.KeyValue, len(attributes))
374 copy(cp, attributes)
375 return attrOpt{set: attribute.NewSet(cp...)}
376 }
377