1// Copyright The OpenTelemetry Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package metric // import "go.opentelemetry.io/otel/metric" 16 17import ( 18 "context" 19 20 "go.opentelemetry.io/otel/label" 21 "go.opentelemetry.io/otel/metric/number" 22 "go.opentelemetry.io/otel/unit" 23) 24 25// MeterProvider supports named Meter instances. 26type MeterProvider interface { 27 // Meter creates an implementation of the Meter interface. 28 // The instrumentationName must be the name of the library providing 29 // instrumentation. This name may be the same as the instrumented code 30 // only if that code provides built-in instrumentation. If the 31 // instrumentationName is empty, then a implementation defined default 32 // name will be used instead. 33 Meter(instrumentationName string, opts ...MeterOption) Meter 34} 35 36// Meter is the creator of metric instruments. 37// 38// An uninitialized Meter is a no-op implementation. 39type Meter struct { 40 impl MeterImpl 41 name, version string 42} 43 44// RecordBatch atomically records a batch of measurements. 45func (m Meter) RecordBatch(ctx context.Context, ls []label.KeyValue, ms ...Measurement) { 46 if m.impl == nil { 47 return 48 } 49 m.impl.RecordBatch(ctx, ls, ms...) 50} 51 52// NewBatchObserver creates a new BatchObserver that supports 53// making batches of observations for multiple instruments. 54func (m Meter) NewBatchObserver(callback BatchObserverFunc) BatchObserver { 55 return BatchObserver{ 56 meter: m, 57 runner: newBatchAsyncRunner(callback), 58 } 59} 60 61// NewInt64Counter creates a new integer Counter instrument with the 62// given name, customized with options. May return an error if the 63// name is invalid (e.g., empty) or improperly registered (e.g., 64// duplicate registration). 65func (m Meter) NewInt64Counter(name string, options ...InstrumentOption) (Int64Counter, error) { 66 return wrapInt64CounterInstrument( 67 m.newSync(name, CounterInstrumentKind, number.Int64Kind, options)) 68} 69 70// NewFloat64Counter creates a new floating point Counter with the 71// given name, customized with options. May return an error if the 72// name is invalid (e.g., empty) or improperly registered (e.g., 73// duplicate registration). 74func (m Meter) NewFloat64Counter(name string, options ...InstrumentOption) (Float64Counter, error) { 75 return wrapFloat64CounterInstrument( 76 m.newSync(name, CounterInstrumentKind, number.Float64Kind, options)) 77} 78 79// NewInt64UpDownCounter creates a new integer UpDownCounter instrument with the 80// given name, customized with options. May return an error if the 81// name is invalid (e.g., empty) or improperly registered (e.g., 82// duplicate registration). 83func (m Meter) NewInt64UpDownCounter(name string, options ...InstrumentOption) (Int64UpDownCounter, error) { 84 return wrapInt64UpDownCounterInstrument( 85 m.newSync(name, UpDownCounterInstrumentKind, number.Int64Kind, options)) 86} 87 88// NewFloat64UpDownCounter creates a new floating point UpDownCounter with the 89// given name, customized with options. May return an error if the 90// name is invalid (e.g., empty) or improperly registered (e.g., 91// duplicate registration). 92func (m Meter) NewFloat64UpDownCounter(name string, options ...InstrumentOption) (Float64UpDownCounter, error) { 93 return wrapFloat64UpDownCounterInstrument( 94 m.newSync(name, UpDownCounterInstrumentKind, number.Float64Kind, options)) 95} 96 97// NewInt64ValueRecorder creates a new integer ValueRecorder instrument with the 98// given name, customized with options. May return an error if the 99// name is invalid (e.g., empty) or improperly registered (e.g., 100// duplicate registration). 101func (m Meter) NewInt64ValueRecorder(name string, opts ...InstrumentOption) (Int64ValueRecorder, error) { 102 return wrapInt64ValueRecorderInstrument( 103 m.newSync(name, ValueRecorderInstrumentKind, number.Int64Kind, opts)) 104} 105 106// NewFloat64ValueRecorder creates a new floating point ValueRecorder with the 107// given name, customized with options. May return an error if the 108// name is invalid (e.g., empty) or improperly registered (e.g., 109// duplicate registration). 110func (m Meter) NewFloat64ValueRecorder(name string, opts ...InstrumentOption) (Float64ValueRecorder, error) { 111 return wrapFloat64ValueRecorderInstrument( 112 m.newSync(name, ValueRecorderInstrumentKind, number.Float64Kind, opts)) 113} 114 115// NewInt64ValueObserver creates a new integer ValueObserver instrument 116// with the given name, running a given callback, and customized with 117// options. May return an error if the name is invalid (e.g., empty) 118// or improperly registered (e.g., duplicate registration). 119func (m Meter) NewInt64ValueObserver(name string, callback Int64ObserverFunc, opts ...InstrumentOption) (Int64ValueObserver, error) { 120 if callback == nil { 121 return wrapInt64ValueObserverInstrument(NoopAsync{}, nil) 122 } 123 return wrapInt64ValueObserverInstrument( 124 m.newAsync(name, ValueObserverInstrumentKind, number.Int64Kind, opts, 125 newInt64AsyncRunner(callback))) 126} 127 128// NewFloat64ValueObserver creates a new floating point ValueObserver with 129// the given name, running a given callback, and customized with 130// options. May return an error if the name is invalid (e.g., empty) 131// or improperly registered (e.g., duplicate registration). 132func (m Meter) NewFloat64ValueObserver(name string, callback Float64ObserverFunc, opts ...InstrumentOption) (Float64ValueObserver, error) { 133 if callback == nil { 134 return wrapFloat64ValueObserverInstrument(NoopAsync{}, nil) 135 } 136 return wrapFloat64ValueObserverInstrument( 137 m.newAsync(name, ValueObserverInstrumentKind, number.Float64Kind, opts, 138 newFloat64AsyncRunner(callback))) 139} 140 141// NewInt64SumObserver creates a new integer SumObserver instrument 142// with the given name, running a given callback, and customized with 143// options. May return an error if the name is invalid (e.g., empty) 144// or improperly registered (e.g., duplicate registration). 145func (m Meter) NewInt64SumObserver(name string, callback Int64ObserverFunc, opts ...InstrumentOption) (Int64SumObserver, error) { 146 if callback == nil { 147 return wrapInt64SumObserverInstrument(NoopAsync{}, nil) 148 } 149 return wrapInt64SumObserverInstrument( 150 m.newAsync(name, SumObserverInstrumentKind, number.Int64Kind, opts, 151 newInt64AsyncRunner(callback))) 152} 153 154// NewFloat64SumObserver creates a new floating point SumObserver with 155// the given name, running a given callback, and customized with 156// options. May return an error if the name is invalid (e.g., empty) 157// or improperly registered (e.g., duplicate registration). 158func (m Meter) NewFloat64SumObserver(name string, callback Float64ObserverFunc, opts ...InstrumentOption) (Float64SumObserver, error) { 159 if callback == nil { 160 return wrapFloat64SumObserverInstrument(NoopAsync{}, nil) 161 } 162 return wrapFloat64SumObserverInstrument( 163 m.newAsync(name, SumObserverInstrumentKind, number.Float64Kind, opts, 164 newFloat64AsyncRunner(callback))) 165} 166 167// NewInt64UpDownSumObserver creates a new integer UpDownSumObserver instrument 168// with the given name, running a given callback, and customized with 169// options. May return an error if the name is invalid (e.g., empty) 170// or improperly registered (e.g., duplicate registration). 171func (m Meter) NewInt64UpDownSumObserver(name string, callback Int64ObserverFunc, opts ...InstrumentOption) (Int64UpDownSumObserver, error) { 172 if callback == nil { 173 return wrapInt64UpDownSumObserverInstrument(NoopAsync{}, nil) 174 } 175 return wrapInt64UpDownSumObserverInstrument( 176 m.newAsync(name, UpDownSumObserverInstrumentKind, number.Int64Kind, opts, 177 newInt64AsyncRunner(callback))) 178} 179 180// NewFloat64UpDownSumObserver creates a new floating point UpDownSumObserver with 181// the given name, running a given callback, and customized with 182// options. May return an error if the name is invalid (e.g., empty) 183// or improperly registered (e.g., duplicate registration). 184func (m Meter) NewFloat64UpDownSumObserver(name string, callback Float64ObserverFunc, opts ...InstrumentOption) (Float64UpDownSumObserver, error) { 185 if callback == nil { 186 return wrapFloat64UpDownSumObserverInstrument(NoopAsync{}, nil) 187 } 188 return wrapFloat64UpDownSumObserverInstrument( 189 m.newAsync(name, UpDownSumObserverInstrumentKind, number.Float64Kind, opts, 190 newFloat64AsyncRunner(callback))) 191} 192 193// NewInt64ValueObserver creates a new integer ValueObserver instrument 194// with the given name, running in a batch callback, and customized with 195// options. May return an error if the name is invalid (e.g., empty) 196// or improperly registered (e.g., duplicate registration). 197func (b BatchObserver) NewInt64ValueObserver(name string, opts ...InstrumentOption) (Int64ValueObserver, error) { 198 if b.runner == nil { 199 return wrapInt64ValueObserverInstrument(NoopAsync{}, nil) 200 } 201 return wrapInt64ValueObserverInstrument( 202 b.meter.newAsync(name, ValueObserverInstrumentKind, number.Int64Kind, opts, b.runner)) 203} 204 205// NewFloat64ValueObserver creates a new floating point ValueObserver with 206// the given name, running in a batch callback, and customized with 207// options. May return an error if the name is invalid (e.g., empty) 208// or improperly registered (e.g., duplicate registration). 209func (b BatchObserver) NewFloat64ValueObserver(name string, opts ...InstrumentOption) (Float64ValueObserver, error) { 210 if b.runner == nil { 211 return wrapFloat64ValueObserverInstrument(NoopAsync{}, nil) 212 } 213 return wrapFloat64ValueObserverInstrument( 214 b.meter.newAsync(name, ValueObserverInstrumentKind, number.Float64Kind, opts, 215 b.runner)) 216} 217 218// NewInt64SumObserver creates a new integer SumObserver instrument 219// with the given name, running in a batch callback, and customized with 220// options. May return an error if the name is invalid (e.g., empty) 221// or improperly registered (e.g., duplicate registration). 222func (b BatchObserver) NewInt64SumObserver(name string, opts ...InstrumentOption) (Int64SumObserver, error) { 223 if b.runner == nil { 224 return wrapInt64SumObserverInstrument(NoopAsync{}, nil) 225 } 226 return wrapInt64SumObserverInstrument( 227 b.meter.newAsync(name, SumObserverInstrumentKind, number.Int64Kind, opts, b.runner)) 228} 229 230// NewFloat64SumObserver creates a new floating point SumObserver with 231// the given name, running in a batch callback, and customized with 232// options. May return an error if the name is invalid (e.g., empty) 233// or improperly registered (e.g., duplicate registration). 234func (b BatchObserver) NewFloat64SumObserver(name string, opts ...InstrumentOption) (Float64SumObserver, error) { 235 if b.runner == nil { 236 return wrapFloat64SumObserverInstrument(NoopAsync{}, nil) 237 } 238 return wrapFloat64SumObserverInstrument( 239 b.meter.newAsync(name, SumObserverInstrumentKind, number.Float64Kind, opts, 240 b.runner)) 241} 242 243// NewInt64UpDownSumObserver creates a new integer UpDownSumObserver instrument 244// with the given name, running in a batch callback, and customized with 245// options. May return an error if the name is invalid (e.g., empty) 246// or improperly registered (e.g., duplicate registration). 247func (b BatchObserver) NewInt64UpDownSumObserver(name string, opts ...InstrumentOption) (Int64UpDownSumObserver, error) { 248 if b.runner == nil { 249 return wrapInt64UpDownSumObserverInstrument(NoopAsync{}, nil) 250 } 251 return wrapInt64UpDownSumObserverInstrument( 252 b.meter.newAsync(name, UpDownSumObserverInstrumentKind, number.Int64Kind, opts, b.runner)) 253} 254 255// NewFloat64UpDownSumObserver creates a new floating point UpDownSumObserver with 256// the given name, running in a batch callback, and customized with 257// options. May return an error if the name is invalid (e.g., empty) 258// or improperly registered (e.g., duplicate registration). 259func (b BatchObserver) NewFloat64UpDownSumObserver(name string, opts ...InstrumentOption) (Float64UpDownSumObserver, error) { 260 if b.runner == nil { 261 return wrapFloat64UpDownSumObserverInstrument(NoopAsync{}, nil) 262 } 263 return wrapFloat64UpDownSumObserverInstrument( 264 b.meter.newAsync(name, UpDownSumObserverInstrumentKind, number.Float64Kind, opts, 265 b.runner)) 266} 267 268// MeterImpl returns the underlying MeterImpl of this Meter. 269func (m Meter) MeterImpl() MeterImpl { 270 return m.impl 271} 272 273// newAsync constructs one new asynchronous instrument. 274func (m Meter) newAsync( 275 name string, 276 mkind InstrumentKind, 277 nkind number.Kind, 278 opts []InstrumentOption, 279 runner AsyncRunner, 280) ( 281 AsyncImpl, 282 error, 283) { 284 if m.impl == nil { 285 return NoopAsync{}, nil 286 } 287 desc := NewDescriptor(name, mkind, nkind, opts...) 288 desc.config.InstrumentationName = m.name 289 desc.config.InstrumentationVersion = m.version 290 return m.impl.NewAsyncInstrument(desc, runner) 291} 292 293// newSync constructs one new synchronous instrument. 294func (m Meter) newSync( 295 name string, 296 metricKind InstrumentKind, 297 numberKind number.Kind, 298 opts []InstrumentOption, 299) ( 300 SyncImpl, 301 error, 302) { 303 if m.impl == nil { 304 return NoopSync{}, nil 305 } 306 desc := NewDescriptor(name, metricKind, numberKind, opts...) 307 desc.config.InstrumentationName = m.name 308 desc.config.InstrumentationVersion = m.version 309 return m.impl.NewSyncInstrument(desc) 310} 311 312// MeterMust is a wrapper for Meter interfaces that panics when any 313// instrument constructor encounters an error. 314type MeterMust struct { 315 meter Meter 316} 317 318// BatchObserverMust is a wrapper for BatchObserver that panics when 319// any instrument constructor encounters an error. 320type BatchObserverMust struct { 321 batch BatchObserver 322} 323 324// Must constructs a MeterMust implementation from a Meter, allowing 325// the application to panic when any instrument constructor yields an 326// error. 327func Must(meter Meter) MeterMust { 328 return MeterMust{meter: meter} 329} 330 331// NewInt64Counter calls `Meter.NewInt64Counter` and returns the 332// instrument, panicking if it encounters an error. 333func (mm MeterMust) NewInt64Counter(name string, cos ...InstrumentOption) Int64Counter { 334 if inst, err := mm.meter.NewInt64Counter(name, cos...); err != nil { 335 panic(err) 336 } else { 337 return inst 338 } 339} 340 341// NewFloat64Counter calls `Meter.NewFloat64Counter` and returns the 342// instrument, panicking if it encounters an error. 343func (mm MeterMust) NewFloat64Counter(name string, cos ...InstrumentOption) Float64Counter { 344 if inst, err := mm.meter.NewFloat64Counter(name, cos...); err != nil { 345 panic(err) 346 } else { 347 return inst 348 } 349} 350 351// NewInt64UpDownCounter calls `Meter.NewInt64UpDownCounter` and returns the 352// instrument, panicking if it encounters an error. 353func (mm MeterMust) NewInt64UpDownCounter(name string, cos ...InstrumentOption) Int64UpDownCounter { 354 if inst, err := mm.meter.NewInt64UpDownCounter(name, cos...); err != nil { 355 panic(err) 356 } else { 357 return inst 358 } 359} 360 361// NewFloat64UpDownCounter calls `Meter.NewFloat64UpDownCounter` and returns the 362// instrument, panicking if it encounters an error. 363func (mm MeterMust) NewFloat64UpDownCounter(name string, cos ...InstrumentOption) Float64UpDownCounter { 364 if inst, err := mm.meter.NewFloat64UpDownCounter(name, cos...); err != nil { 365 panic(err) 366 } else { 367 return inst 368 } 369} 370 371// NewInt64ValueRecorder calls `Meter.NewInt64ValueRecorder` and returns the 372// instrument, panicking if it encounters an error. 373func (mm MeterMust) NewInt64ValueRecorder(name string, mos ...InstrumentOption) Int64ValueRecorder { 374 if inst, err := mm.meter.NewInt64ValueRecorder(name, mos...); err != nil { 375 panic(err) 376 } else { 377 return inst 378 } 379} 380 381// NewFloat64ValueRecorder calls `Meter.NewFloat64ValueRecorder` and returns the 382// instrument, panicking if it encounters an error. 383func (mm MeterMust) NewFloat64ValueRecorder(name string, mos ...InstrumentOption) Float64ValueRecorder { 384 if inst, err := mm.meter.NewFloat64ValueRecorder(name, mos...); err != nil { 385 panic(err) 386 } else { 387 return inst 388 } 389} 390 391// NewInt64ValueObserver calls `Meter.NewInt64ValueObserver` and 392// returns the instrument, panicking if it encounters an error. 393func (mm MeterMust) NewInt64ValueObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64ValueObserver { 394 if inst, err := mm.meter.NewInt64ValueObserver(name, callback, oos...); err != nil { 395 panic(err) 396 } else { 397 return inst 398 } 399} 400 401// NewFloat64ValueObserver calls `Meter.NewFloat64ValueObserver` and 402// returns the instrument, panicking if it encounters an error. 403func (mm MeterMust) NewFloat64ValueObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64ValueObserver { 404 if inst, err := mm.meter.NewFloat64ValueObserver(name, callback, oos...); err != nil { 405 panic(err) 406 } else { 407 return inst 408 } 409} 410 411// NewInt64SumObserver calls `Meter.NewInt64SumObserver` and 412// returns the instrument, panicking if it encounters an error. 413func (mm MeterMust) NewInt64SumObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64SumObserver { 414 if inst, err := mm.meter.NewInt64SumObserver(name, callback, oos...); err != nil { 415 panic(err) 416 } else { 417 return inst 418 } 419} 420 421// NewFloat64SumObserver calls `Meter.NewFloat64SumObserver` and 422// returns the instrument, panicking if it encounters an error. 423func (mm MeterMust) NewFloat64SumObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64SumObserver { 424 if inst, err := mm.meter.NewFloat64SumObserver(name, callback, oos...); err != nil { 425 panic(err) 426 } else { 427 return inst 428 } 429} 430 431// NewInt64UpDownSumObserver calls `Meter.NewInt64UpDownSumObserver` and 432// returns the instrument, panicking if it encounters an error. 433func (mm MeterMust) NewInt64UpDownSumObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64UpDownSumObserver { 434 if inst, err := mm.meter.NewInt64UpDownSumObserver(name, callback, oos...); err != nil { 435 panic(err) 436 } else { 437 return inst 438 } 439} 440 441// NewFloat64UpDownSumObserver calls `Meter.NewFloat64UpDownSumObserver` and 442// returns the instrument, panicking if it encounters an error. 443func (mm MeterMust) NewFloat64UpDownSumObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64UpDownSumObserver { 444 if inst, err := mm.meter.NewFloat64UpDownSumObserver(name, callback, oos...); err != nil { 445 panic(err) 446 } else { 447 return inst 448 } 449} 450 451// NewBatchObserver returns a wrapper around BatchObserver that panics 452// when any instrument constructor returns an error. 453func (mm MeterMust) NewBatchObserver(callback BatchObserverFunc) BatchObserverMust { 454 return BatchObserverMust{ 455 batch: mm.meter.NewBatchObserver(callback), 456 } 457} 458 459// NewInt64ValueObserver calls `BatchObserver.NewInt64ValueObserver` and 460// returns the instrument, panicking if it encounters an error. 461func (bm BatchObserverMust) NewInt64ValueObserver(name string, oos ...InstrumentOption) Int64ValueObserver { 462 if inst, err := bm.batch.NewInt64ValueObserver(name, oos...); err != nil { 463 panic(err) 464 } else { 465 return inst 466 } 467} 468 469// NewFloat64ValueObserver calls `BatchObserver.NewFloat64ValueObserver` and 470// returns the instrument, panicking if it encounters an error. 471func (bm BatchObserverMust) NewFloat64ValueObserver(name string, oos ...InstrumentOption) Float64ValueObserver { 472 if inst, err := bm.batch.NewFloat64ValueObserver(name, oos...); err != nil { 473 panic(err) 474 } else { 475 return inst 476 } 477} 478 479// NewInt64SumObserver calls `BatchObserver.NewInt64SumObserver` and 480// returns the instrument, panicking if it encounters an error. 481func (bm BatchObserverMust) NewInt64SumObserver(name string, oos ...InstrumentOption) Int64SumObserver { 482 if inst, err := bm.batch.NewInt64SumObserver(name, oos...); err != nil { 483 panic(err) 484 } else { 485 return inst 486 } 487} 488 489// NewFloat64SumObserver calls `BatchObserver.NewFloat64SumObserver` and 490// returns the instrument, panicking if it encounters an error. 491func (bm BatchObserverMust) NewFloat64SumObserver(name string, oos ...InstrumentOption) Float64SumObserver { 492 if inst, err := bm.batch.NewFloat64SumObserver(name, oos...); err != nil { 493 panic(err) 494 } else { 495 return inst 496 } 497} 498 499// NewInt64UpDownSumObserver calls `BatchObserver.NewInt64UpDownSumObserver` and 500// returns the instrument, panicking if it encounters an error. 501func (bm BatchObserverMust) NewInt64UpDownSumObserver(name string, oos ...InstrumentOption) Int64UpDownSumObserver { 502 if inst, err := bm.batch.NewInt64UpDownSumObserver(name, oos...); err != nil { 503 panic(err) 504 } else { 505 return inst 506 } 507} 508 509// NewFloat64UpDownSumObserver calls `BatchObserver.NewFloat64UpDownSumObserver` and 510// returns the instrument, panicking if it encounters an error. 511func (bm BatchObserverMust) NewFloat64UpDownSumObserver(name string, oos ...InstrumentOption) Float64UpDownSumObserver { 512 if inst, err := bm.batch.NewFloat64UpDownSumObserver(name, oos...); err != nil { 513 panic(err) 514 } else { 515 return inst 516 } 517} 518 519// Descriptor contains all the settings that describe an instrument, 520// including its name, metric kind, number kind, and the configurable 521// options. 522type Descriptor struct { 523 name string 524 instrumentKind InstrumentKind 525 numberKind number.Kind 526 config InstrumentConfig 527} 528 529// NewDescriptor returns a Descriptor with the given contents. 530func NewDescriptor(name string, ikind InstrumentKind, nkind number.Kind, opts ...InstrumentOption) Descriptor { 531 return Descriptor{ 532 name: name, 533 instrumentKind: ikind, 534 numberKind: nkind, 535 config: NewInstrumentConfig(opts...), 536 } 537} 538 539// Name returns the metric instrument's name. 540func (d Descriptor) Name() string { 541 return d.name 542} 543 544// InstrumentKind returns the specific kind of instrument. 545func (d Descriptor) InstrumentKind() InstrumentKind { 546 return d.instrumentKind 547} 548 549// Description provides a human-readable description of the metric 550// instrument. 551func (d Descriptor) Description() string { 552 return d.config.Description 553} 554 555// Unit describes the units of the metric instrument. Unitless 556// metrics return the empty string. 557func (d Descriptor) Unit() unit.Unit { 558 return d.config.Unit 559} 560 561// NumberKind returns whether this instrument is declared over int64, 562// float64, or uint64 values. 563func (d Descriptor) NumberKind() number.Kind { 564 return d.numberKind 565} 566 567// InstrumentationName returns the name of the library that provided 568// instrumentation for this instrument. 569func (d Descriptor) InstrumentationName() string { 570 return d.config.InstrumentationName 571} 572 573// InstrumentationVersion returns the version of the library that provided 574// instrumentation for this instrument. 575func (d Descriptor) InstrumentationVersion() string { 576 return d.config.InstrumentationVersion 577} 578