TT Lab
Get started
Learn Learning paths Courses

OTCA — OpenTelemetry Certified Associate

Six orders, but the dashboard drew nine

Continue in TT Lab

Goal

With the real OpenTelemetry Python SDK, measure in turn a reader's temporality, the default histogram boundaries, how to change boundaries, attributes, and dropping with views, and how asynchronous instruments report, and then assemble three views into a single MeterProvider.

Why it matters

Even for the same counter, what the backend has to interpret differs depending on whether you send cumulative or delta. If you read the two mixed together, orders are counted twice, and if you put values in seconds into the default boundaries meant for milliseconds, the histogram piles up in one bucket and the quantiles become meaningless. An attribute such as a customer ID increases the data points and drives up cost. Correcting this with SDK configuration (readers and views) without changing the instrumentation code is the reason the API and SDK were separated.

Prepared environment

/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py init places shop.py (which records orders, cart, payment time, and debug metrics in a fixed order) and pipeline.py (seven functions to fill in) in /root/otca-metrics/. /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show N assembles a MeterProvider of the lab-dev image's OpenTelemetry Python SDK 1.44.0 (/opt/otel-lab) with your pipeline.py, and prints the data points collected twice after shop records. No network, Collector, or API key is used. The grader reruns your functions with the same SDK and compares the behavior with the numbers you wrote. Be sure to run with /opt/otel-lab/bin/python.

Steps

  1. Create the materials with /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py init. Fix reader_cumulative() in /root/otca-metrics/pipeline.py to return the default InMemoryMetricReader, and then run /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 1. shop.py records 3 orders and collects, records 3 more and collects again. In /root/otca-metrics/01-cumulative.txt, write first= and second= (the orders sums).
  2. Fix reader_delta() to return a reader that requests DELTA for Counter only, and run /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 2. In /root/otca-metrics/02-delta.txt, write first=, second=, and double_counted= (the sum a dashboard would draw if the two cumulative values from step 1 were mistaken for deltas and added).
  3. Fix reader_all_delta() to request DELTA for all of Counter, UpDownCounter, Histogram, and ObservableCounter, and run /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 3. In /root/otca-metrics/03-updown.txt, write cumulative_second= (the second value of cart.items seen with reader_delta) and delta_second= (the value seen with reader_all_delta).
  4. With /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 4, look at the histogram of checkout.duration (unit s, values 0.2, 0.35, 0.8, 1.4) collected without a view. In /root/otca-metrics/04-default-buckets.txt, write boundaries= (the number of default boundaries), nonzero_bucket_index= (the position of the bucket the values fell into, counting from 0), and nonzero_bucket_count=.
  5. Fix views_buckets() to return a list of Views that applies the boundaries 0.25, 0.5, 1, 2 only to checkout.duration. In /root/otca-metrics/05-view-buckets.txt, write the bucket counts from the result of /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 5 as bucket_counts= (comma-separated, the last being above 2). Other metrics must stay as they are.
  6. Fix views_cardinality() to return a list of Views that keeps only route as the attribute key of orders. Look at /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 6 and, in /root/otca-metrics/06-view-attributes.txt, write points_before= (the number of orders points in the first collection without a view), points_after=, and checkout_sum= (the /checkout value in the first collection with the view applied).
  7. In register_async(meter, source), make queue.processed observe source.processed() as an ObservableCounter and queue.depth observe source.depth() as an ObservableGauge. Look at /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 7 (using reader_all_delta) and, in /root/otca-metrics/07-async.txt, write processed_delta_second= and depth_second=. On each call, source returns processed 10, 25 and depth 7, 4.
  8. Fix provider(reader) to return a MeterProvider that has the reader it received and three views — the buckets from step 5, the attribute reduction from step 6, and a DropAggregation that drops debug.cache.lookups. The grader collects twice with reader_all_delta() and checks orders (delta by route), checkout.duration (new boundaries), cart.items, and the dropped debug metric together. Look at it first with /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 8.

Notes

Collect twice and 3 is followed by 6

Create the materials with /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py init. Fix reader_cumulative() in /root/otca-metrics/pipeline.py to return the default InMemoryMetricReader, and then run /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 1. shop.py records 3 orders and collects, records 3 more and collects again. In /root/otca-metrics/01-cumulative.txt, write first= and second= (the orders sums).

If the reader does not request a temporality separately, the SDK sends the cumulative value from the start.

Receiving delta, and what happens when you mix them

Fix reader_delta() to return a reader that requests DELTA for Counter only, and run /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 2. In /root/otca-metrics/02-delta.txt, write first=, second=, and double_counted= (the sum a dashboard would draw if the two cumulative values from step 1 were mistaken for deltas and added).

preferred_temporality is a dictionary from instrument class to temporality. If you add up cumulative values, the earlier interval is counted twice.

UpDownCounter must be requested separately

Fix reader_all_delta() to request DELTA for all of Counter, UpDownCounter, Histogram, and ObservableCounter, and run /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 3. In /root/otca-metrics/03-updown.txt, write cumulative_second= (the second value of cart.items seen with reader_delta) and delta_second= (the value seen with reader_all_delta).

reader_delta changed only Counter. For the cart, +5 and -2 are recorded, followed by +1.

Values in seconds piled into one bucket

With /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 4, look at the histogram of checkout.duration (unit s, values 0.2, 0.35, 0.8, 1.4) collected without a view. In /root/otca-metrics/04-default-buckets.txt, write boundaries= (the number of default boundaries), nonzero_bucket_index= (the position of the bucket the values fell into, counting from 0), and nonzero_bucket_count=.

The SDK's default boundaries are values meant for latency in milliseconds. Look at the first boundary and the second boundary.

Change the boundaries with a view

Fix views_buckets() to return a list of Views that applies the boundaries 0.25, 0.5, 1, 2 only to checkout.duration. In /root/otca-metrics/05-view-buckets.txt, write the bucket counts from the result of /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 5 as bucket_counts= (comma-separated, the last being above 2). Other metrics must stay as they are.

A View chooses its target with instrument_name and changes the aggregation with aggregation. If you do not choose a target, it applies to every instrument.

Dropping the customer ID reduces the points

Fix views_cardinality() to return a list of Views that keeps only route as the attribute key of orders. Look at /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 6 and, in /root/otca-metrics/06-view-attributes.txt, write points_before= (the number of orders points in the first collection without a view), points_after=, and checkout_sum= (the /checkout value in the first collection with the view applied).

There is one data point per attribute combination. If you choose only the keys to keep, measurements that differ only in the other keys are merged and the total is preserved.

An asynchronous counter reports the cumulative value

In register_async(meter, source), make queue.processed observe source.processed() as an ObservableCounter and queue.depth observe source.depth() as an ObservableGauge. Look at /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 7 (using reader_all_delta) and, in /root/otca-metrics/07-async.txt, write processed_delta_second= and depth_second=. On each call, source returns processed 10, 25 and depth 7, 4.

An asynchronous counter callback returns the cumulative absolute value so far. The SDK computes the delta as the difference from the previous observation. A gauge is not added.

Three views in one provider

Fix provider(reader) to return a MeterProvider that has the reader it received and three views — the buckets from step 5, the attribute reduction from step 6, and a DropAggregation that drops debug.cache.lookups. The grader collects twice with reader_all_delta() and checks orders (delta by route), checkout.duration (new boundaries), cart.items, and the dropped debug metric together. Look at it first with /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 8.

Views are passed in when you create the MeterProvider. If several views match one instrument, several streams are created, so narrow the target of each view.