instrument.go

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