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