-
Notifications
You must be signed in to change notification settings - Fork 894
/
sdk.md
1571 lines (1216 loc) · 71.9 KB
/
sdk.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!--- Hugo front matter used to generate the website version of this page:
linkTitle: SDK
--->
# Metrics SDK
**Status**: [Mixed](../document-status.md)
<details>
<summary>Table of Contents</summary>
<!-- toc -->
- [MeterProvider](#meterprovider)
* [MeterProvider Creation](#meterprovider-creation)
* [Meter Creation](#meter-creation)
* [Configuration](#configuration)
* [Shutdown](#shutdown)
* [ForceFlush](#forceflush)
* [View](#view)
+ [Instrument selection criteria](#instrument-selection-criteria)
+ [Stream configuration](#stream-configuration)
+ [Measurement processing](#measurement-processing)
+ [View examples](#view-examples)
* [Aggregation](#aggregation)
+ [Drop Aggregation](#drop-aggregation)
+ [Default Aggregation](#default-aggregation)
+ [Sum Aggregation](#sum-aggregation)
+ [Last Value Aggregation](#last-value-aggregation)
+ [Histogram Aggregations](#histogram-aggregations)
- [Explicit Bucket Histogram Aggregation](#explicit-bucket-histogram-aggregation)
- [Base2 Exponential Bucket Histogram Aggregation](#base2-exponential-bucket-histogram-aggregation)
* [Handle all normal values](#handle-all-normal-values)
* [Support a minimum and maximum scale](#support-a-minimum-and-maximum-scale)
* [Use the maximum scale for single measurements](#use-the-maximum-scale-for-single-measurements)
* [Maintain the ideal scale](#maintain-the-ideal-scale)
* [Observations inside asynchronous callbacks](#observations-inside-asynchronous-callbacks)
* [Cardinality limits](#cardinality-limits)
+ [Configuration](#configuration-1)
+ [Overflow attribute](#overflow-attribute)
+ [Synchronous instrument cardinality limits](#synchronous-instrument-cardinality-limits)
+ [Asynchronous instrument cardinality limits](#asynchronous-instrument-cardinality-limits)
- [Meter](#meter)
* [Duplicate instrument registration](#duplicate-instrument-registration)
+ [Name conflict](#name-conflict)
* [Instrument name](#instrument-name)
* [Instrument unit](#instrument-unit)
* [Instrument description](#instrument-description)
* [Instrument advisory parameters](#instrument-advisory-parameters)
- [Attribute limits](#attribute-limits)
- [Exemplar](#exemplar)
* [ExemplarFilter](#exemplarfilter)
* [Built-in ExemplarFilters](#built-in-exemplarfilters)
+ [AlwaysOn](#alwayson)
+ [AlwaysOff](#alwaysoff)
+ [TraceBased](#tracebased)
* [ExemplarReservoir](#exemplarreservoir)
* [Exemplar defaults](#exemplar-defaults)
+ [SimpleFixedSizeExemplarReservoir](#simplefixedsizeexemplarreservoir)
+ [AlignedHistogramBucketExemplarReservoir](#alignedhistogrambucketexemplarreservoir)
- [MetricReader](#metricreader)
* [MetricReader operations](#metricreader-operations)
+ [Collect](#collect)
+ [Shutdown](#shutdown-1)
* [Periodic exporting MetricReader](#periodic-exporting-metricreader)
+ [ForceFlush](#forceflush-1)
- [MetricExporter](#metricexporter)
* [Push Metric Exporter](#push-metric-exporter)
+ [Interface Definition](#interface-definition)
- [Export(batch)](#exportbatch)
- [ForceFlush()](#forceflush)
- [Shutdown()](#shutdown)
* [Pull Metric Exporter](#pull-metric-exporter)
- [MetricProducer](#metricproducer)
* [Interface Definition](#interface-definition-1)
+ [Produce() batch](#produce-batch)
- [Defaults and configuration](#defaults-and-configuration)
- [Numerical limits handling](#numerical-limits-handling)
- [Compatibility requirements](#compatibility-requirements)
- [Concurrency requirements](#concurrency-requirements)
<!-- tocstop -->
</details>
Users of OpenTelemetry need a way for instrumentation interactions with the
OpenTelemetry API to actually produce telemetry. The OpenTelemetry SDK
(henceforth referred to as the SDK) is an implementation of the OpenTelemetry
API that provides users with this functionally.
All language implementations of OpenTelemetry MUST provide an SDK.
## MeterProvider
**Status**: [Stable](../document-status.md)
A `MeterProvider` MUST provide a way to allow a [Resource](../resource/sdk.md) to
be specified. If a `Resource` is specified, it SHOULD be associated with all the
metrics produced by any `Meter` from the `MeterProvider`. The [tracing SDK
specification](../trace/sdk.md#additional-span-interfaces) has provided some
suggestions regarding how to implement this efficiently.
### MeterProvider Creation
The SDK SHOULD allow the creation of multiple independent `MeterProvider`s.
### Meter Creation
It SHOULD only be possible to create `Meter` instances through a `MeterProvider`
(see [API](./api.md#meterprovider)).
The `MeterProvider` MUST implement the [Get a Meter API](api.md#get-a-meter).
The input provided by the user MUST be used to create
an [`InstrumentationScope`](../glossary.md#instrumentation-scope) instance which
is stored on the created `Meter`.
In the case where an invalid `name` (null or empty string) is specified, a
working Meter MUST be returned as a fallback rather than returning null or
throwing an exception, its `name` SHOULD keep the original invalid value, and a
message reporting that the specified value is invalid SHOULD be logged.
When a Schema URL is passed as an argument when creating a `Meter` the emitted
telemetry for that `Meter` MUST be associated with the Schema URL, provided
that the emitted data format is capable of representing such association.
### Configuration
Configuration (i.e. [MetricExporters](#metricexporter),
[MetricReaders](#metricreader) and [Views](#view)) MUST be owned by the
`MeterProvider`. The configuration MAY be applied at the time of `MeterProvider`
creation if appropriate.
The `MeterProvider` MAY provide methods to update the configuration. If
configuration is updated (e.g., adding a `MetricReader`), the updated
configuration MUST also apply to all already returned `Meters` (i.e. it MUST NOT
matter whether a `Meter` was obtained from the `MeterProvider` before or after
the configuration change). Note: Implementation-wise, this could mean that
`Meter` instances have a reference to their `MeterProvider` and access
configuration only via this reference.
### Shutdown
This method provides a way for provider to do any cleanup required.
`Shutdown` MUST be called only once for each `MeterProvider` instance. After the
call to `Shutdown`, subsequent attempts to get a `Meter` are not allowed. SDKs
SHOULD return a valid no-op Meter for these calls, if possible.
`Shutdown` SHOULD provide a way to let the caller know whether it succeeded,
failed or timed out.
`Shutdown` SHOULD complete or abort within some timeout. `Shutdown` MAY be
implemented as a blocking API or an asynchronous API which notifies the caller
via a callback or an event. [OpenTelemetry SDK](../overview.md#sdk) authors MAY
decide if they want to make the shutdown timeout configurable.
`Shutdown` MUST be implemented at least by invoking `Shutdown` on all registered
[MetricReader](#metricreader) and [MetricExporter](#metricexporter) instances.
### ForceFlush
This method provides a way for provider to notify the registered
[MetricReader](#metricreader) instances that have an associated
[Push Metric Exporter](#push-metric-exporter), so they can do as much
as they could to collect and send the metrics.
Note: [Pull Metric Exporter](#pull-metric-exporter) can only send the
data when it is being asked by the scraper, so `ForceFlush` would not make much
sense.
`ForceFlush` MUST invoke `ForceFlush` on all registered
[MetricReader](#metricreader) instances that implement `ForceFlush`.
`ForceFlush` SHOULD provide a way to let the caller know whether it succeeded,
failed or timed out. `ForceFlush` SHOULD return some **ERROR** status if there
is an error condition; and if there is no error condition, it should return some
**NO ERROR** status, language implementations MAY decide how to model **ERROR**
and **NO ERROR**.
`ForceFlush` SHOULD complete or abort within some timeout. `ForceFlush` MAY be
implemented as a blocking API or an asynchronous API which notifies the caller
via a callback or an event. [OpenTelemetry SDK](../overview.md#sdk) authors MAY
decide if they want to make the flush timeout configurable.
### View
A `View` provides SDK users with the flexibility to customize the metrics that
are output by the SDK. Here are some examples when a `View` might be needed:
* Customize which [Instruments](./api.md#instrument) are to be
processed/ignored. For example, an [instrumented
library](../glossary.md#instrumented-library) can provide both temperature and
humidity, but the application developer might only want temperature.
* Customize the aggregation - if the default aggregation associated with the
Instrument does not meet the needs of the user. For example, an HTTP client
library might expose HTTP client request duration as
[Histogram](./api.md#histogram) by default, but the application developer
might only want the total count of outgoing requests.
* Customize which attribute(s) are to be reported on metrics. For
example, an HTTP server library might expose HTTP verb (e.g. GET, POST) and
HTTP status code (e.g. 200, 301, 404). The application developer might only
care about HTTP status code (e.g. reporting the total count of HTTP requests
for each HTTP status code). There could also be extreme scenarios in which the
application developer does not need any attributes (e.g. just get the total
count of all incoming requests).
The SDK MUST provide functionality for a user to create Views for a
`MeterProvider`. This functionality MUST accept as inputs the [Instrument
selection criteria](#instrument-selection-criteria) and the resulting [stream
configuration](#stream-configuration).
The SDK MUST provide the means to register Views with a `MeterProvider`.
#### Instrument selection criteria
Instrument selection criteria are the predicates that determine if a View will
be applied to an Instrument or not.
Criteria SHOULD be treated as additive. This means an Instrument has to match
_all_ the provided criteria for the View to be applied. For example, if the
criteria are _instrument name == "Foobar"_ and _instrument type is Histogram_,
it will be treated as _(instrument name == "Foobar") AND (instrument type is
Histogram)_.
The SDK MUST accept the following criteria:
* `name`: The name of the Instrument(s) to match. This `name` is evaluated to
match an Instrument in the following manner.
1. If the value of `name` is `*`, the criterion matches all Instruments.
2. If the value of `name` is exactly the same as an Instrument, then the
criterion matches that instrument.
Additionally, the SDK MAY support wildcard pattern matching for the `name`
criterion using the following characters.
* A question mark (`?`): matches any single character
* An asterisk (`*`): matches any number of any characters including none
If wildcard pattern matching is supported, the `name` criterion will match if
the wildcard pattern is evaluated to match the Instrument name.
If the SDK does not support wildcards in general, it MUST still recognize the
special single asterisk (`*`) character as matching all Instruments.
Users can provide a `name`, but it is up to their discretion. Therefore, the
instrument selection criteria parameter needs to be structured to accept a
`name`, but MUST NOT obligate a user to provide one.
* `type`: The type of Instruments to match. If the value of `type` is the same
as an Instrument's type, then the criterion matches that Instrument.
Users can provide a `type`, but it is up to their discretion. Therefore, the
instrument selection criteria parameter needs to be structured to accept a
`type`, but MUST NOT obligate a user to provide one.
* `unit`: If the value of `unit` is the same as an Instrument's unit, then the
criterion matches that Instrument.
Users can provide a `unit`, but it is up to their discretion. Therefore, the
instrument selection criteria parameter needs to be structured to accept a
`unit`, but MUST NOT obligate a user to provide one.
* `meter_name`: If the value of `meter_name` is the same as the Meter that
created an Instrument, then the criterion matches that Instrument.
Users can provide a `meter_name`, but it is up to their discretion.
Therefore, the instrument selection criteria parameter needs to be structured
to accept a `meter_name`, but MUST NOT obligate a user to provide one.
* `meter_version`: If the value of `meter_version` is the same version as the
Meter that created an Instrument, then the criterion matches that Instrument.
Users can provide a `meter_version`, but it is up to their discretion.
Therefore, the instrument selection criteria parameter needs to be structured
to accept a `meter_version`, but MUST NOT obligate a user to provide one.
* `meter_schema_url`: If the value of `meter_schema_url` is the same schema URL
as the Meter that created an Instrument, then the criterion matches that
Instrument.
Users can provide a `meter_schema_url`, but it is up to their discretion.
Therefore, the instrument selection criteria parameter needs to be structured
to accept a `meter_schema_url`, but MUST NOT obligate a user to provide one.
The SDK MAY accept additional criteria. For example, a strongly typed language
may support point type criterion (e.g. allow the users to select Instruments
based on whether the underlying number is integral or rational). Users can
provide these additional criteria the SDK accepts, but it is up to their
discretion. Therefore, the instrument selection criteria can be structured to
accept the criteria, but MUST NOT obligate a user to provide them.
#### Stream configuration
Stream configuration are the parameters that define the [metric
stream](./data-model.md#events--data-stream--timeseries) a `MeterProvider` will
use to define telemetry pipelines.
The SDK MUST accept the following stream configuration parameters:
* `name`: The metric stream name that SHOULD be used.
In order to avoid conflicts, if a `name` is provided the View SHOULD have an
instrument selector that selects at most one instrument. If the Instrument
selection criteria for a View with a stream configuration `name` parameter
can select more than one instrument (i.e. wildcards) the SDK MAY fail fast in
accordance with initialization [error handling
principles](../error-handling.md#basic-error-handling-principles).
Users can provide a `name`, but it is up to their discretion. Therefore, the
stream configuration parameter needs to be structured to accept a `name`, but
MUST NOT obligate a user to provide one. If the user does not provide a
`name` value, name from the Instrument the View matches MUST be used by
default.
* `description`: The metric stream description that SHOULD be used.
Users can provide a `description`, but it is up to their discretion.
Therefore, the stream configuration parameter needs to be structured to
accept a `description`, but MUST NOT obligate a user to provide one. If the
user does not provide a `description` value, the description from the
Instrument a View matches MUST be used by default.
* `attribute_keys`: A list of attribute keys that MUST be kept, if provided by
the user during the measurement, for the metric stream. All attributes with
keys other than those in the list MUST be ignored.
Users can provide `attribute_keys`, but it is up to their discretion.
Therefore, the stream configuration parameter needs to be structured to
accept `attribute_keys`, but MUST NOT obligate a user to provide them.
If the user does not provide any value, the SDK SHOULD use
the [`Attributes`](./api.md#instrument-advisory-parameters) advisory
parameter configured on the instrument instead. If the `Attributes`
advisory parameter is absent, all attributes MUST be kept.
* `aggregation`: The name of an [aggregation](#aggregation) function to use in
aggregating the metric stream data.
Users can provide an `aggregation`, but it is up to their discretion.
Therefore, the stream configuration parameter needs to be structured to
accept an `aggregation`, but MUST NOT obligate a user to provide one. If the
user does not provide an `aggregation` value, the `MeterProvider` MUST apply
a [default aggregation](#default-aggregation) configurable on the basis of
instrument type according to the [MetricReader](#metricreader) instance.
* **Status**: [Feature-freeze](../document-status.md) - `exemplar_reservoir`: A
functional type that generates an exemplar reservoir a `MeterProvider` will
use when storing exemplars. This functional type needs to be a factory or
callback similar to aggregation selection functionality which allows
different reservoirs to be chosen by the aggregation.
Users can provide an `exemplar_reservoir`, but it is up to their discretion.
Therefore, the stream configuration parameter needs to be structured to
accept an `exemplar_reservoir`, but MUST NOT obligate a user to provide one.
If the user does not provide an `exemplar_reservoir` value, the
`MeterProvider` MUST apply a [default exemplar
reservoir](#exemplar-defaults).
* **Status**: [Experimental](../document-status.md) -
`aggregation_cardinality_limit`: A positive integer value defining the
maximum number of data points allowed to be emitted in a collection cycle by
a single instrument. See [cardinality limits](#cardinality-limits), below.
Users can provide an `aggregation_cardinality_limit`, but it is up to their
discretion. Therefore, the stream configuration parameter needs to be
structured to accept an `aggregation_cardinality_limit`, but MUST NOT
obligate a user to provide one. If the user does not provide an
`aggregation_cardinality_limit` value, the `MeterProvider` MUST apply the
[default aggregation cardinality limit](#metricreader) the `MetricReader` is
configured with.
#### Measurement processing
The SDK SHOULD use the following logic to determine how to process Measurements
made with an Instrument:
* Determine the `MeterProvider` which "owns" the Instrument.
* If the `MeterProvider` has no `View` registered, take the Instrument
and apply the default Aggregation on the basis of instrument kind
according to the [MetricReader](#metricreader) instance's
`aggregation` property.
* If the `MeterProvider` has one or more `View`(s) registered:
* For each View, if the Instrument could match the instrument selection
criteria:
* Try to apply the View's stream configuration. If applying the View
results in [conflicting metric
identities](./data-model.md#opentelemetry-protocol-data-model-producer-recommendations)
the implementation SHOULD apply the View and emit a warning. If it is not
possible to apply the View without producing semantic errors (e.g. the
View sets an asynchronous instrument to use the [Explicit bucket
histogram aggregation](#explicit-bucket-histogram-aggregation)) the
implementation SHOULD emit a warning and proceed as if the View did not
exist.
* If the Instrument could not match with any of the registered `View`(s), the
SDK SHOULD enable the instrument using the default aggregation and temporality.
Users can configure match-all Views using [Drop aggregation](#drop-aggregation)
to disable instruments by default.
#### View examples
The following are examples of an SDK's functionality to create Views for a
`MeterProvider`.
```python
# Python
'''
+------------------+
| MeterProvider |
| Meter A |
| Counter X |
| Histogram Y |
| Meter B |
| Gauge Z |
+------------------+
'''
# metrics from X and Y (reported as Foo and Bar) will be exported
meter_provider
.add_view("X")
.add_view("Foo", instrument_name="Y")
.add_view(
"Bar",
instrument_name="Y",
aggregation=HistogramAggregation(buckets=[5.0, 10.0, 25.0, 50.0, 100.0]))
.add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```
```python
# all the metrics will be exported using the default configuration
meter_provider.add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```
```python
# all the metrics will be exported using the default configuration
meter_provider
.add_view("*") # a wildcard view that matches everything
.add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```
```python
# Counter X will be exported as cumulative sum
meter_provider
.add_view("X", aggregation=SumAggregation())
.add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```
```python
# Counter X will be exported as delta sum
# Histogram Y and Gauge Z will be exported with 2 attributes (a and b)
meter_provider
.add_view("X", aggregation=SumAggregation())
.add_view("*", attribute_keys=["a", "b"])
.add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()),
temporality=lambda kind: Delta if kind in [Counter, AsyncCounter, Histogram] else Cumulative)
```
### Aggregation
An `Aggregation`, as configured via the [View](./sdk.md#view),
informs the SDK on the ways and means to compute
[Aggregated Metrics](./data-model.md#opentelemetry-protocol-data-model)
from incoming Instrument [Measurements](./api.md#measurement).
Note: the term _aggregation_ is used instead of _aggregator_. It is RECOMMENDED
that implementors reserve the "aggregator" term for the future when the SDK
allows custom aggregation implementations.
An `Aggregation` specifies an operation
(i.e. [decomposable aggregate function](https://en.wikipedia.org/wiki/Aggregate_function#Decomposable_aggregate_functions)
like Sum, Histogram, Min, Max, Count)
and optional configuration parameter overrides.
The operation's default configuration parameter values will be used
unless overridden by optional configuration parameter overrides.
Note: Implementors MAY choose the best idiomatic practice for their language to
represent the semantic of an Aggregation and optional configuration parameters.
e.g. The View specifies an Aggregation by string name (i.e. "ExplicitBucketHistogram").
```python
# Use Histogram with custom boundaries
meter_provider
.add_view(
"X",
aggregation="ExplicitBucketHistogram",
aggregation_params={"Boundaries": [0, 10, 100]}
)
```
e.g. The View specifies an Aggregation by class/type instance.
```c#
// Use Histogram with custom boundaries
meterProviderBuilder
.AddView(
instrumentName: "X",
aggregation: new ExplicitBucketHistogramAggregation(
boundaries: new double[] { 0.0, 10.0, 100.0 }
)
);
```
TODO: after we release the initial Stable version of Metrics SDK specification,
we will explore how to allow configuring custom
[ExemplarReservoir](#exemplarreservoir)s with the [View](#view) API.
The SDK MUST provide the following `Aggregation` to support the
[Metric Points](./data-model.md#metric-points) in the
[Metrics Data Model](./data-model.md).
- [Drop](./sdk.md#drop-aggregation)
- [Default](./sdk.md#default-aggregation)
- [Sum](./sdk.md#sum-aggregation)
- [Last Value](./sdk.md#last-value-aggregation)
- [Explicit Bucket Histogram](./sdk.md#explicit-bucket-histogram-aggregation)
The SDK SHOULD provide the following `Aggregation`:
- [Base2 Exponential Bucket Histogram](./sdk.md#base2-exponential-bucket-histogram-aggregation)
#### Drop Aggregation
The Drop Aggregation informs the SDK to ignore/drop all Instrument Measurements
for this Aggregation.
This Aggregation does not have any configuration parameters.
#### Default Aggregation
The Default Aggregation informs the SDK to use the Instrument `kind` to select
an aggregation and `advisory` parameters to influence aggregation configuration
parameters (as noted in the "Selected Aggregation" column).
| Instrument Kind | Selected Aggregation |
|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Counter](./api.md#counter) | [Sum Aggregation](./sdk.md#sum-aggregation) |
| [Asynchronous Counter](./api.md#asynchronous-counter) | [Sum Aggregation](./sdk.md#sum-aggregation) |
| [UpDownCounter](./api.md#updowncounter) | [Sum Aggregation](./sdk.md#sum-aggregation) |
| [Asynchronous UpDownCounter](./api.md#asynchronous-updowncounter) | [Sum Aggregation](./sdk.md#sum-aggregation) |
| [Gauge](./api.md#gauge) | [Last Value Aggregation](./sdk.md#last-value-aggregation) |
| [Asynchronous Gauge](./api.md#asynchronous-gauge) | [Last Value Aggregation](./sdk.md#last-value-aggregation) |
| [Histogram](./api.md#histogram) | [Explicit Bucket Histogram Aggregation](./sdk.md#explicit-bucket-histogram-aggregation), with the `ExplicitBucketBoundaries` [advisory parameter](./api.md#instrument-advisory-parameters) if provided |
This Aggregation does not have any configuration parameters.
#### Sum Aggregation
The Sum Aggregation informs the SDK to collect data for the
[Sum Metric Point](./data-model.md#sums).
The monotonicity of the aggregation is determined by the instrument type:
| Instrument Kind | `SumType` |
| --- | --- |
| [Counter](./api.md#counter) | Monotonic |
| [UpDownCounter](./api.md#updowncounter) | Non-Monotonic |
| [Histogram](./api.md#histogram) | Monotonic |
| [Asynchronous Gauge](./api.md#asynchronous-gauge) | Non-Monotonic |
| [Asynchronous Counter](./api.md#asynchronous-counter) | Monotonic |
| [Asynchronous UpDownCounter](./api.md#asynchronous-updowncounter) | Non-Monotonic |
This Aggregation does not have any configuration parameters.
This Aggregation informs the SDK to collect:
- The arithmetic sum of `Measurement` values.
#### Last Value Aggregation
The Last Value Aggregation informs the SDK to collect data for the
[Gauge Metric Point](./data-model.md#gauge).
This Aggregation does not have any configuration parameters.
This Aggregation informs the SDK to collect:
- The last `Measurement`.
- The timestamp of the last `Measurement`.
#### Histogram Aggregations
All histogram Aggregations inform the SDK to collect:
- Count of `Measurement` values in population.
- Arithmetic sum of `Measurement` values in population. This SHOULD NOT be collected when used with
instruments that record negative measurements (e.g. `UpDownCounter` or `ObservableGauge`).
- Min (optional) `Measurement` value in population.
- Max (optional) `Measurement` value in population.
##### Explicit Bucket Histogram Aggregation
The Explicit Bucket Histogram Aggregation informs the SDK to collect data for
the [Histogram Metric Point](./data-model.md#histogram) using a set of
explicit boundary values for histogram bucketing.
This Aggregation honors the following configuration parameters:
| Key | Value | Default Value | Description |
| --- | --- | --- | --- |
| Boundaries | double\[\] | [ 0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000 ] | Array of increasing values representing explicit bucket boundary values.<br><br>The Default Value represents the following buckets (heavily influenced by the default buckets of Prometheus clients, e.g. [Java](https://github.com/prometheus/client_java/blob/6730f3e32199d6bf0e963b306ff69ef08ac5b178/simpleclient/src/main/java/io/prometheus/client/Histogram.java#L88) and [Go](https://github.com/prometheus/client_golang/blob/83d56b1144a0c2eb10d399e7abbae3333bebc463/prometheus/histogram.go#L68)):<br>(-∞, 0], (0, 5.0], (5.0, 10.0], (10.0, 25.0], (25.0, 50.0], (50.0, 75.0], (75.0, 100.0], (100.0, 250.0], (250.0, 500.0], (500.0, 750.0], (750.0, 1000.0], (1000.0, 2500.0], (2500.0, 5000.0], (5000.0, 7500.0], (7500.0, 10000.0], (10000.0, +∞). SDKs SHOULD use the default value when boundaries are not explicitly provided, unless they have good reasons to use something different (e.g. for backward compatibility reasons in a stable SDK release). |
| RecordMinMax | true, false | true | Whether to record min and max. |
Explicit buckets are stated in terms of their upper boundary. Buckets
are exclusive of their lower boundary and inclusive of their upper
bound (except at positive infinity). A measurement is defined to fall
into the greatest-numbered bucket with boundary that is greater than
or equal to the measurement.
##### Base2 Exponential Bucket Histogram Aggregation
The Base2 Exponential Histogram Aggregation informs the SDK to collect data
for the [Exponential Histogram Metric
Point](./data-model.md#exponentialhistogram), which uses a base-2 exponential
formula to determine bucket boundaries and an integer `scale`
parameter to control resolution. Implementations adjust scale as necessary given
the data.
This Aggregation honors the following configuration parameters:
| Key | Value | Default Value | Description |
|--------------|-------------|---------------|--------------------------------------------------------------------------------------------------------------|
| MaxSize | integer | 160 | Maximum number of buckets in each of the positive and negative ranges, not counting the special zero bucket. |
| MaxScale | integer | 20 | Maximum `scale` factor. |
| RecordMinMax | true, false | true | Whether to record min and max. |
The default of 160 buckets is selected to establish default support
for a high-resolution histogram able to cover a long-tail latency
distribution from 1ms to 100s with less than 5% relative error.
Because 160 can be factored into `10 * 2**K`, maximum contrast is
relatively simple to derive for scale `K`:
| Scale | Maximum data contrast at 10 * 2**K buckets |
|-------|--------------------------------------------|
| K+2 | 5.657 (2**(10/4)) |
| K+1 | 32 (2**(10/2)) |
| K | 1024 (2**10) |
| K-1 | 1048576 (2**20) |
The following table shows how the ideal scale for 160 buckets is
calculated as a function of the input range:
| Input range | Contrast | Ideal Scale | Base | Relative error |
|-------------|----------|-------------|----------|----------------|
| 1ms - 4ms | 4 | 6 | 1.010889 | 0.542% |
| 1ms - 20ms | 20 | 5 | 1.021897 | 1.083% |
| 1ms - 1s | 10**3 | 4 | 1.044274 | 2.166% |
| 1ms - 100s | 10**5 | 3 | 1.090508 | 4.329% |
| 1μs - 10s | 10**7 | 2 | 1.189207 | 8.643% |
Note that relative error is calculated as half of the bucket width
divided by the bucket midpoint, which is the same in every bucket.
Using the bucket from [1, base), we have `(bucketWidth / 2) /
bucketMidpoint = ((base - 1) / 2) / ((base + 1) / 2) = (base - 1) /
(base + 1)`.
This Aggregation uses the notion of "ideal" scale. The ideal scale is
either:
1. The `MaxScale` (see configuration parameters), generally used for
single-value histogram Aggregations where scale is not otherwise constrained.
2. The largest value of scale such that no more than the maximum number of
buckets are needed to represent the full range of input data in either of the
positive or negative ranges.
###### Handle all normal values
Implementations are REQUIRED to accept the entire normal range of IEEE
floating point values (i.e., all values except for +Inf, -Inf and NaN
values).
Implementations SHOULD NOT incorporate non-normal values (i.e., +Inf,
-Inf, and NaNs) into the `sum`, `min`, and `max` fields, because these
values do not map into a valid bucket.
Implementations MAY round subnormal values away from zero to the
nearest normal value.
###### Support a minimum and maximum scale
The implementation MUST maintain reasonable minimum and maximum scale
parameters that the automatic scale parameter will not exceed. The maximum scale
is defined by the `MaxScale` configuration parameter.
###### Use the maximum scale for single measurements
When the histogram contains not more than one value in either of the
positive or negative ranges, the implementation SHOULD use the maximum
scale.
###### Maintain the ideal scale
Implementations SHOULD adjust the histogram scale as necessary to
maintain the best resolution possible, within the constraint of
maximum size (max number of buckets). Best resolution (highest scale)
is achieved when the number of positive or negative range buckets
exceeds half the maximum size, such that increasing scale by one would
not be possible given the size constraint.
### Observations inside asynchronous callbacks
Callback functions MUST be invoked for the specific `MetricReader`
performing collection, such that observations made or produced by
executing callbacks only apply to the intended `MetricReader` during
collection.
The implementation SHOULD disregard the use of asynchronous instrument
APIs outside of registered callbacks.
The implementation SHOULD use a timeout to prevent indefinite callback
execution.
The implementation MUST complete the execution of all callbacks for a
given instrument before starting a subsequent round of collection.
The implementation SHOULD NOT produce aggregated metric data for a
previously-observed attribute set which is not observed during a successful
callback. See [MetricReader](#metricreader) for more details on the persistence
of metrics across successive collections.
### Cardinality limits
**Status**: [Experimental](../document-status.md)
SDKs SHOULD support being configured with a cardinality limit. A cardinality
limit is the hard limit on the number of metric streams that can be collected.
#### Configuration
The cardinality limit for an aggregation is defined in one of three ways:
1. A [view](#view) with criteria matching the instrument an aggregation is
created for has an `aggregation_cardinality_limit` value defined for the
stream, that value SHOULD be used.
2. If there is no matching view, but the `MetricReader` defines a default
cardinality limit value based on the instrument an aggregation is created
for, that value SHOULD be used.
3. If none of the previous values are defined, the default value of 2000 SHOULD
be used.
#### Overflow attribute
An overflow attribute set is defined, containing a single attribute
`otel.metric.overflow` having (boolean) value `true`, which is used to
report a synthetic aggregation of the metric events that could not be
independently aggregated because of the limit.
The SDK MUST create an Aggregator with the overflow attribute set
prior to reaching the cardinality limit and use it to aggregate events
for which the correct Aggregator could not be created. The maximum
number of distinct, non-overflow attributes is one less than the
limit, as a result.
#### Synchronous instrument cardinality limits
Aggregators for synchronous instruments with cumulative temporality MUST
continue to export all attribute sets that were observed prior to the
beginning of overflow. Metric events corresponding with attribute sets that
were not observed prior to the overflow will be reflected in a single data
point described by (only) the overflow attribute.
Aggregators of synchronous instruments with delta aggregation temporality MAY
choose an arbitrary subset of attribute sets to output to maintain the stated
cardinality limit.
Regardless of aggregation temporality, the SDK MUST ensure that every
metric event is reflected in exactly one Aggregator, which is either
an Aggregator associated with the correct attribute set or an
aggregator associated with the overflow attribute set.
Events MUST NOT be double-counted or dropped during an
overflow.
#### Asynchronous instrument cardinality limits
Aggregators of asynchronous instruments SHOULD prefer the first-observed
attributes in the callback when limiting cardinality, regardless of
temporality.
## Meter
Distinct meters MUST be treated as separate namespaces for the purposes of detecting
[duplicate instrument registrations](#duplicate-instrument-registration).
### Duplicate instrument registration
A _duplicate instrument registration_ occurs when more than one Instrument of
the same [`name`](./api.md#instrument-name-syntax) is created for identical
Meters from the same MeterProvider but they have different [identifying
fields](./api.md#instrument).
Whenever this occurs, users still need to be able to make measurements with the
duplicate instrument. This means that the Meter MUST return a functional
instrument that can be expected to export data even if this will cause
[semantic error in the data
model](data-model.md#opentelemetry-protocol-data-model-producer-recommendations).
Additionally, users need to be informed about this error. Therefore, when a
duplicate instrument registration occurs, and it is not corrected with a View,
a warning SHOULD be emitted. The emitted warning SHOULD include information for
the user on how to resolve the conflict, if possible.
1. If the potential conflict involves multiple `description`
properties, setting the `description` through a configured View
SHOULD avoid the warning.
2. If the potential conflict involves instruments that can be distinguished by
a supported View selector (e.g. name, instrument kind) a renaming View
recipe SHOULD be included in the warning.
3. Otherwise (e.g., use of multiple units), the SDK SHOULD pass through the
data by reporting both `Metric` objects and emit a generic warning
describing the duplicate instrument registration.
It is unspecified whether or under which conditions the same or
different Instrument instance will be returned as a result of
duplicate instrument registration. The term _identical_ applied to
Instruments describes instances where all [identifying
fields](./api.md#instrument) are equal. The term _distinct_ applied
to Instruments describes instances where at least one field value is
different.
To accommodate [the recommendations from the data
model](data-model.md#opentelemetry-protocol-data-model-producer-recommendations),
the SDK MUST aggregate data from [identical Instruments](api.md#instrument)
together in its export pipeline.
#### Name conflict
The [`name`](./api.md#instrument-name-syntax) of an Instrument is defined to be
case-insensitive. If an SDK uses a case-sensitive encoding to represent this
`name`, a duplicate instrument registration will occur when a user passes
multiple casings of the same `name`. When this happens, the Meter MUST return
an instrument using the first-seen instrument name and log an appropriate error
as described above.
For example, if a user creates an instrument with the name `requestCount` and
then makes another request to the same `Meter` to create an instrument with the
name `RequestCount`, in both cases an instrument with the name `requestCount`
needs to be returned to the user and a log message needs to be emitted for the
second request.
### Instrument name
When a Meter creates an instrument, it SHOULD validate the instrument name
conforms to the [instrument name syntax](./api.md#instrument-name-syntax)
If the instrument name does not conform to this syntax, the Meter SHOULD emit
an error notifying the user about the invalid name. It is left unspecified if a
valid instrument is also returned.
### Instrument unit
When a Meter creates an instrument, it SHOULD NOT validate the instrument unit.
If a unit is not provided or the unit is null, the Meter MUST treat it the same
as an empty unit string.
### Instrument description
When a Meter creates an instrument, it SHOULD NOT validate the instrument
description. If a description is not provided or the description is null, the
Meter MUST treat it the same as an empty description string.
### Instrument advisory parameters
**Status**: [Experimental](../document-status.md)
When a Meter creates an instrument, it SHOULD validate the instrument advisory
parameters. If an advisory parameter is not valid, the Meter SHOULD emit an error
notifying the user and proceed as if the parameter was not provided.
If multiple [identical Instruments](api.md#instrument) are created with
different advice parameters, the Meter MUST return an instrument using the
first-seen advice parameters and log an appropriate error as described in
[duplicate instrument registrations](#duplicate-instrument-registration).
## Attribute limits
**Status**: [Stable](../document-status.md)
Attributes which belong to Metrics are exempt from the
[common rules of attribute limits](../common/README.md#attribute-limits) at this
time. Attribute truncation or deletion could affect identity of metric time
series and the topic requires further analysis.
## Exemplar
**Status**: [Feature-freeze](../document-status.md)
Exemplars are example data points for aggregated data. They provide specific
context to otherwise general aggregations. Exemplars allow correlation between
aggregated metric data and the original API calls where measurements are
recorded. Exemplars work for trace-metric correlation across any metric, not
just those that can also be derived from `Span`s.
An [Exemplar](./data-model.md#exemplars) is a recorded
[Measurement](./api.md#measurement) that exposes the following pieces of
information:
- The `value` of the `Measurement` that was recorded by the API call.
- The `time` the API call was made to record a `Measurement`.
- The set of [Attributes](../common/README.md#attribute) associated with the
`Measurement` not already included in a metric data point.
- The associated [trace id and span
id](../trace/api.md#retrieving-the-traceid-and-spanid) of the active [Span
within Context](../trace/api.md#determining-the-parent-span-from-a-context) of
the `Measurement` at API call time.
For example, if a user has configured a `View` to preserve the attributes: `X`
and `Y`, but the user records a measurement as follows:
```javascript
const span = tracer.startSpan('makeRequest');
api.context.with(api.trace.setSpan(api.context.active(), span), () => {
// Record a measurement.
cache_miss_counter.add(1, {"X": "x-value", "Y": "y-value", "Z": "z-value"});
...
span.end();
})
```
Then an exemplar output in OTLP would consist of:
- The `value` of 1.
- The `time` when the `add` method was called
- The `Attributes` of `{"Z": "z-value"}`, as these are not preserved in the
resulting metric point.
- The trace/span id for the `makeRequest` span.
While the metric data point for the counter would carry the attributes `X` and
`Y`.
A Metric SDK MUST provide a mechanism to sample `Exemplar`s from measurements
via the `ExemplarFilter` and `ExemplarReservoir` hooks.
`Exemplar` sampling SHOULD be turned off by default. If `Exemplar` sampling is
off, the SDK MUST NOT have overhead related to exemplar sampling.
A Metric SDK MUST allow exemplar sampling to leverage the configuration of
metric aggregation. For example, Exemplar sampling of histograms should be able
to leverage bucket boundaries.
A Metric SDK SHOULD provide extensible hooks for Exemplar sampling, specifically:
- `ExemplarFilter`: filter which measurements can become exemplars.
- `ExemplarReservoir`: storage and sampling of exemplars.
### ExemplarFilter
The `ExemplarFilter` interface MUST provide a method to determine if a
measurement should be sampled. Sampled here simply makes the measurement
eligible for being included as an exemplar. `ExemplarReservoir` makes the final
decision if a measurement becomes an exemplar.
This interface SHOULD have access to:
- The `value` of the measurement.
- The complete set of `Attributes` of the measurement.
- The [Context](../context/README.md) of the measurement, which covers the
[Baggage](../baggage/api.md) and the current active
[Span](../trace/api.md#span).
- A `timestamp` that best represents when the measurement was taken.
### Built-in ExemplarFilters
OpenTelemetry supports a number of built-in exemplar filters to choose from.
The default is `TraceBased`.
#### AlwaysOn
An ExemplarFilter which makes all measurements eligible for being an Exemplar.
#### AlwaysOff
An ExemplarFilter which makes no measurements eligible for being an Exemplar.
Using this ExemplarFilter is as good as disabling Exemplar feature.
#### TraceBased
An ExemplarFilter which makes those measurements eligible for being an
Exemplar, which are recorded in the context of a sampled parent span.
### ExemplarReservoir
The `ExemplarReservoir` interface MUST provide a method to offer measurements
to the reservoir and another to collect accumulated Exemplars.
The "offer" method SHOULD accept measurements, including:
- The `value` of the measurement.
- The complete set of `Attributes` of the measurement.
- The [Context](../context/README.md) of the measurement, which covers the
[Baggage](../baggage/api.md) and the current active
[Span](../trace/api.md#span).
- A `timestamp` that best represents when the measurement was taken.
The "offer" method SHOULD have the ability to pull associated trace and span
information without needing to record full context. In other words, current
span context and baggage can be inspected at this point.
The "offer" method does not need to store all measurements it is given and
MAY further sample beyond the `ExemplarFilter`.
The "collect" method MUST return accumulated `Exemplar`s. Exemplars are expected
to abide by the `AggregationTemporality` of any metric point they are recorded
with. In other words, Exemplars reported against a metric data point SHOULD have
occurred within the start/stop timestamps of that point. SDKs are free to
decide whether "collect" should also reset internal storage for delta temporal
aggregation collection, or use a more optimal implementation.
`Exemplar`s MUST retain any attributes available in the measurement that
are not preserved by aggregation or view configuration. Specifically, at a