Skip to content

Commit 8d6ed1e

Browse files
committed
nits
1 parent 8dc8e37 commit 8d6ed1e

File tree

1 file changed

+78
-68
lines changed

1 file changed

+78
-68
lines changed

docs/metrics.md

Lines changed: 78 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ Status: **Work-In-Progress**
2727
* [Memory Preallocation](#memory-preallocation)
2828
* [Metrics Correlation](#metrics-correlation)
2929
* [Modelling Metric Attributes](#modelling-metric-attributes)
30-
* [Common Issues Leading to Missing Metrics](#common-issues-that-lead-to-missing-metrics)
30+
* [Common Issues Leading to Missing
31+
Metrics](#common-issues-that-lead-to-missing-metrics)
3132

3233
</details>
3334

@@ -61,8 +62,8 @@ instances with the same name. `Meter` is fairly expensive and meant to be reused
6162
throughout the application. For most applications, a `Meter` should be obtained
6263
from `global` and saved for re-use.
6364

64-
> [!IMPORTANT]
65-
> Create your `Meter` instance once at initialization time and store it for reuse throughout your application's lifecycle.
65+
> [!IMPORTANT] Create your `Meter` instance once at initialization time and
66+
> store it for reuse throughout your application's lifecycle.
6667
6768
The fully qualified module name might be a good option for the Meter name.
6869
Optionally, one may create a meter with version, schema_url, and additional
@@ -95,13 +96,12 @@ instruments to their corresponding Rust SDK types.
9596

9697
:heavy_check_mark: You should understand and pick the right instrument type.
9798

98-
> [!NOTE]
99-
> Picking the right instrument type for your use case is crucial to ensure the
100-
correct semantics and performance. Check the [Instrument
99+
> [!NOTE] Picking the right instrument type for your use case is crucial to
100+
> ensure the correct semantics and performance. Check the [Instrument
101101
Selection](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/supplementary-guidelines.md#instrument-selection)
102102
section from the supplementary guidelines for more information.
103103

104-
| OpenTelemetry Specification | OTel Rust Instrument Type |
104+
| OpenTelemetry Specification | OpenTelemetry Rust Instrument Type |
105105
| --------------------------- | -------------------- |
106106
| [Asynchronous Counter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-counter) | [`ObservableCounter`](https://docs.rs/opentelemetry/latest/opentelemetry/metrics/struct.ObservableCounter.html) |
107107
| [Asynchronous Gauge](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-gauge) | [`ObservableGauge`](https://docs.rs/opentelemetry/latest/opentelemetry/metrics/struct.ObservableGauge.html) |
@@ -128,8 +128,7 @@ path. Instead, the cloned instance should be stored and reused.
128128
:stop_sign: You should avoid changing the order of attributes while reporting
129129
measurements.
130130

131-
> [!WARNING]
132-
> The last line of code has bad performance since the attributes are
131+
> [!WARNING] The last line of code has bad performance since the attributes are
133132
> not following the same order as before:
134133
135134
```rust
@@ -141,7 +140,9 @@ counter.add(8, &[KeyValue::new("name", "lemon"), KeyValue::new("color", "yellow"
141140
```
142141

143142
:heavy_check_mark: If feasible, provide the attributes sorted by `Key`s in
144-
ascending order to minimize memory usage within the Metrics SDK. Using consistent attribute ordering allows the SDK to efficiently reuse internal data structures.
143+
ascending order to minimize memory usage within the Metrics SDK. Using
144+
consistent attribute ordering allows the SDK to efficiently reuse internal data
145+
structures.
145146

146147
```rust
147148
// Good practice: Consistent attribute ordering
@@ -236,8 +237,7 @@ fn setup_metrics(meter: &opentelemetry::metrics::Meter) {
236237
}
237238
```
238239

239-
> [!NOTE]
240-
> The callbacks in the Observable instruments are invoked by the SDK
240+
> [!NOTE] The callbacks in the Observable instruments are invoked by the SDK
241241
> during each export cycle.
242242
243243
## MeterProvider Management
@@ -290,44 +290,44 @@ follows while implementing the metrics aggregation logic:
290290
2. [**Cardinality Limits**](#cardinality-limits): the aggregation logic respects
291291
[cardinality
292292
limits](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#cardinality-limits),
293-
so the SDK does not use an indefinite amount of memory in the event of a cardinality
294-
explosion.
293+
so the SDK does not use an indefinite amount of memory in the event of a
294+
cardinality explosion.
295295
3. [**Memory Preallocation**](#memory-preallocation): SDK tries to pre-allocate
296296
the memory it needs at each instrument creation time.
297297

298298
### Example
299299

300-
Let us take the following example of OTel Rust metrics being used to track the
301-
number of fruits sold:
300+
Let us take the following example of OpenTelemetry Rust metrics being used to
301+
track the number of fruits sold:
302302

303303
* During the time range (T0, T1]:
304-
* value = 1, name = `apple`, color = `red`
305-
* value = 2, name = `lemon`, color = `yellow`
304+
* value = 1, color = `red`, name = `apple`
305+
* value = 2, color = `yellow`, name = `lemon`
306306
* During the time range (T1, T2]:
307307
* no fruit has been sold
308308
* During the time range (T2, T3]:
309-
* value = 5, name = `apple`, color = `red`
310-
* value = 2, name = `apple`, color = `green`
311-
* value = 4, name = `lemon`, color = `yellow`
312-
* value = 2, name = `lemon`, color = `yellow`
313-
* value = 1, name = `lemon`, color = `yellow`
314-
* value = 3, name = `lemon`, color = `yellow`
309+
* value = 5, color = `red`, name = `apple`
310+
* value = 2, color = `green`, name = `apple`
311+
* value = 4, color = `yellow`, name = `lemon`
312+
* value = 2, color = `yellow`, name = `lemon`
313+
* value = 1, color = `yellow`, name = `lemon`
314+
* value = 3, color = `yellow`, name = `lemon`
315315

316316
### Example - Cumulative Aggregation Temporality
317317

318318
If we aggregate and export the metrics using [Cumulative Aggregation
319319
Temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#temporality):
320320

321321
* (T0, T1]
322-
* attributes: {name = `apple`, color = `red`}, count: `1`
323-
* attributes: {name = `lemon`, color = `yellow`}, count: `2`
322+
* attributes: {color = `red`, name = `apple`}, count: `1`
323+
* attributes: {color = `yellow`, name = `lemon`}, count: `2`
324324
* (T0, T2]
325-
* attributes: {name = `apple`, color = `red`}, count: `1`
326-
* attributes: {name = `lemon`, color = `yellow`}, count: `2`
325+
* attributes: {color = `red`, name = `apple`}, count: `1`
326+
* attributes: {color = `yellow`, name = `lemon`}, count: `2`
327327
* (T0, T3]
328-
* attributes: {name = `apple`, color = `red`}, count: `6`
329-
* attributes: {name = `apple`, color = `green`}, count: `2`
330-
* attributes: {name = `lemon`, color = `yellow`}, count: `12`
328+
* attributes: {color = `red`, name = `apple`}, count: `6`
329+
* attributes: {color = `green`, name = `apple`}, count: `2`
330+
* attributes: {color = `yellow`, name = `lemon`}, count: `12`
331331

332332
Note that the start time is not advanced, and the exported values are the
333333
cumulative total of what happened since the beginning.
@@ -338,14 +338,14 @@ If we aggregate and export the metrics using [Delta Aggregation
338338
Temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#temporality):
339339

340340
* (T0, T1]
341-
* attributes: {name = `apple`, color = `red`}, count: `1`
342-
* attributes: {name = `lemon`, color = `yellow`}, count: `2`
341+
* attributes: {color = `red`, name = `apple`}, count: `1`
342+
* attributes: {color = `yellow`, name = `lemon`}, count: `2`
343343
* (T1, T2]
344344
* nothing since we do not have any measurement received
345345
* (T2, T3]
346-
* attributes: {name = `apple`, color = `red`}, count: `5`
347-
* attributes: {name = `apple`, color = `green`}, count: `2`
348-
* attributes: {name = `lemon`, color = `yellow`}, count: `10`
346+
* attributes: {color = `red`, name = `apple`}, count: `5`
347+
* attributes: {color = `green`, name = `apple`}, count: `2`
348+
* attributes: {color = `yellow`, name = `lemon`}, count: `10`
349349

350350
Note that the start time is advanced after each export, and only the delta since
351351
last export is exported, allowing the SDK to "forget" previous state.
@@ -358,7 +358,8 @@ Rust aggregates data locally and only exports the aggregated metrics.
358358
Using the [fruit example](#example), there are six measurements reported during
359359
the time range `(T2, T3]`. Instead of exporting each individual measurement
360360
event, the SDK aggregates them and exports only the summarized results. This
361-
summarization process, illustrated in the following diagram, is known as pre-aggregation:
361+
summarization process, illustrated in the following diagram, is known as
362+
pre-aggregation:
362363

363364
```mermaid
364365
graph LR
@@ -395,26 +396,26 @@ Pre-aggregation offers several advantages:
395396
computational load on downstream systems, enabling them to focus on analysis
396397
and storage.
397398

398-
> [!NOTE]
399-
> There is no ability to opt out of pre-aggregation in OpenTelemetry.
399+
> [!NOTE] There is no ability to opt out of pre-aggregation in OpenTelemetry.
400400
401401
### Cardinality Limits
402402

403403
The number of distinct combinations of attributes for a given metric is referred
404404
to as the cardinality of that metric. Taking the [fruit example](#example), if
405405
we know that we can only have apple/lemon as the name, red/yellow/green as the
406-
color, then we can say the cardinality is 6 (i.e., 2 names × 3 colors = 6 combinations). No matter how many
407-
fruits we sell, we can always use the following table to summarize the total
408-
number of fruits based on the name and color.
409-
410-
| Name | Color | Count |
411-
| ----- | ------ | ----- |
412-
| apple | red | 6 |
413-
| apple | yellow | 0 |
414-
| apple | green | 2 |
415-
| lemon | red | 0 |
416-
| lemon | yellow | 12 |
417-
| lemon | green | 0 |
406+
color, then we can say the cardinality is 6 (i.e., 2 names × 3 colors = 6
407+
combinations). No matter how many fruits we sell, we can always use the
408+
following table to summarize the total number of fruits based on the name and
409+
color.
410+
411+
| Color | Name | Count |
412+
| ------ | ----- | ----- |
413+
| red | apple | 6 |
414+
| yellow | apple | 0 |
415+
| green | apple | 2 |
416+
| red | lemon | 0 |
417+
| yellow | lemon | 12 |
418+
| green | lemon | 0 |
418419

419420
In other words, we know how much memory and network are needed to collect and
420421
transmit these metrics, regardless of the traffic pattern or volume.
@@ -429,7 +430,8 @@ example, it can cause:
429430
* Surprisingly high costs in the observability system
430431
* Excessive memory consumption in your application
431432
* Poor query performance in your metrics backend
432-
* Potential denial-of-service vulnerability that could be exploited by bad actors
433+
* Potential denial-of-service vulnerability that could be exploited by bad
434+
actors
433435

434436
[Cardinality
435437
limit](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#cardinality-limits)
@@ -460,8 +462,8 @@ see much higher cardinality due to:
460462
(This is only applicable to Delta temporality)
461463

462464
Therefore, the actual cardinality in your metrics backend can be orders of
463-
magnitude higher than what any single OTel SDK process handles in an export
464-
cycle.
465+
magnitude higher than what any single OpenTelemetry SDK process handles in an
466+
export cycle.
465467

466468
#### Cardinality Limits - Implications
467469

@@ -533,13 +535,14 @@ During a busy sales period at time (T3, T4], we record:
533535

534536
The exported metrics would be:
535537

536-
* attributes: {name = `apple`, color = `red`, store_location = `Downtown`},
538+
* attributes: {color = `red`, name = `apple`, store_location = `Downtown`},
537539
count: `10`
538-
* attributes: {name = `lemon`, color = `yellow`, store_location = `Uptown`},
540+
* attributes: {color = `yellow`, name = `lemon`, store_location = `Uptown`},
539541
count: `5`
540-
* attributes: {name = `apple`, color = `green`, store_location = `Downtown`},
542+
* attributes: {color = `green`, name = `apple`, store_location = `Downtown`},
541543
count: `8`
542-
* attributes: {`otel.metric.overflow` = `true`}, count: `3` ← Notice this special overflow attribute
544+
* attributes: {`otel.metric.overflow` = `true`}, count: `3` ← Notice this
545+
special overflow attribute
543546

544547
If we later query "How many red apples were sold?" the answer would be 10, not
545548
13, because the Midtown sales were folded into the overflow bucket. Similarly,
@@ -577,8 +580,8 @@ A better alternative is to use a concept in OpenTelemetry called
577580
Exemplars provide a mechanism to correlate metrics with traces by sampling
578581
specific measurements and attaching trace context to them.
579582

580-
> [!NOTE]
581-
> Currently, exemplars are not yet implemented in the OpenTelemetry Rust SDK.
583+
> [!NOTE] Currently, exemplars are not yet implemented in the OpenTelemetry Rust
584+
> SDK.
582585
583586
## Modelling Metric Attributes
584587

@@ -604,8 +607,9 @@ attributes can come from different sources:
604607
Follow these guidelines when deciding where to attach metric attributes:
605608

606609
* **For static attributes** (constant throughout the process lifetime):
607-
* **Resource-level attributes**: If the dimension applies to all metrics (e.g., hostname, datacenter),
608-
model it as a Resource attribute, or better yet, let the collector add these automatically.
610+
* **Resource-level attributes**: If the dimension applies to all metrics
611+
(e.g., hostname, datacenter), model it as a Resource attribute, or better
612+
yet, let the collector add these automatically.
609613

610614
```rust
611615
// Example: Setting resource-level attributes
@@ -615,8 +619,9 @@ Follow these guidelines when deciding where to attach metric attributes:
615619
]);
616620
```
617621

618-
* **Meter-level attributes**: If the dimension applies only to a subset of metrics (e.g., library version),
619-
model it as meter-level attributes via `meter_with_scope`.
622+
* **Meter-level attributes**: If the dimension applies only to a subset of
623+
metrics (e.g., library version), model it as meter-level attributes via
624+
`meter_with_scope`.
620625

621626
```rust
622627
// Example: Setting meter-level attributes
@@ -629,7 +634,8 @@ Follow these guidelines when deciding where to attach metric attributes:
629634

630635
* **For dynamic attributes** (values that change during execution):
631636
* Report these via the Metrics API with each measurement.
632-
* Be mindful that [cardinality limits](#cardinality-limits) apply to these attributes.
637+
* Be mindful that [cardinality limits](#cardinality-limits) apply to these
638+
attributes.
633639

634640
```rust
635641
// Example: Using dynamic attributes with each measurement
@@ -643,10 +649,14 @@ Follow these guidelines when deciding where to attach metric attributes:
643649

644650
Common pitfalls that can result in missing metrics include:
645651

646-
1. **Invalid instrument names** - OpenTelemetry will not collect metrics from instruments using invalid names. See the [specification for valid syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-name-syntax).
652+
1. **Invalid instrument names** - OpenTelemetry will not collect metrics from
653+
instruments using invalid names. See the [specification for valid
654+
syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-name-syntax).
647655

648-
2. **Not calling `shutdown` on the MeterProvider** - Ensure you properly call `shutdown` at application termination to flush any pending metrics.
656+
2. **Not calling `shutdown` on the MeterProvider** - Ensure you properly call
657+
`shutdown` at application termination to flush any pending metrics.
649658

650-
3. **Cardinality explosion** - When too many unique attribute combinations are used, some metrics may be placed in the overflow bucket.
659+
3. **Cardinality explosion** - When too many unique attribute combinations are
660+
used, some metrics may be placed in the overflow bucket.
651661

652662
// TODO: Add more specific examples

0 commit comments

Comments
 (0)