TT Lab
Get started
Learn Learning paths Courses

OTCA — OpenTelemetry Certified Associate

Seven Instruments, Twelve LogRecord Fields, and the Schema URL

Continue in TT Lab

In one line

The instruments of the metrics API fall into Counter, UpDownCounter, Gauge, and Histogram and their asynchronous (callback) variants, and the Sum that the SDK emits carries a temporality of delta or cumulative. The log signal consists of the LogRecord data model, which has twelve fields, and a bridge API that connects existing logging libraries to that model. A schema URL is a version marker that lets consumers interpret data even after semantic conventions change. The sources are the specifications for the metrics API, the metrics data model, the logs data model, and telemetry schemas.

Why this was needed

"Request count," "queue length," and "room temperature" are all numbers, but their natures differ. A request count only goes up, a queue length goes up and down, and a temperature is meaningless to add together. Instruments are split into kinds so that this nature is declared at the API stage and the SDK can choose a suitable default aggregation. The specification overview puts it this way: "record the raw measurements, and the end user chooses how to aggregate them."

Logs are a problem in the opposite direction. Every language already has a logging library, and you cannot tell people to throw away those logs and rewrite them against a new API. So the log signal starts from "how do we move existing logs into a common model and connect them with traces?" Schemas are the same kind of problem — if an attribute name in a semantic convention changes, the dashboards and backends that expected that name break.

How it works

The seven kinds of instruments

An instrument is defined by a name, a kind, a unit (optional), and a description (optional). Combining the concepts document and the API specification gives this.

Instrument Sync/async Nature Recording operation
Counter Synchronous Monotonically increasing (only goes up) Add
Asynchronous Counter Asynchronous Monotonically increasing; reports the cumulative value at observation time Callback
UpDownCounter Synchronous Both increases and decreases (queue length) Add
Asynchronous UpDownCounter Asynchronous A value that can be summed (process heap size) Callback
Gauge Synchronous A value that cannot be summed (noise level), recorded when it changes Record
Asynchronous Gauge Asynchronous A value that cannot be summed (room temperature), reported at observation time Callback
Histogram Synchronous A value whose distribution matters (request latency) Record

Synchronous instruments are called directly inside application logic, and their measurements can be associated with the Context (that is, the current span). For asynchronous instruments, you register a callback, and the SDK calls it only at collection time — the specification's example is reading a sensor temperature every 15 seconds. Asynchronous measurements are not associated with a Context. The specification adds that synchronous and asynchronous here have nothing to do with the programming async pattern. The UpDownCounter description includes the guidance "if the value is monotonically increasing, use a Counter."

Each instrument has a default aggregation, and with a View you can change it, ignore a particular instrument, or choose the attributes to report. The concepts document also explains the cardinality limit — the default upper bound on unique attribute combinations per metric stream is 2000, and when it overflows, measurements are not dropped but folded into a single otel.metric.overflow=true attribute. The totals are right, but folded measurements lose their other attributes, so queries that filter on those attributes undercount.

temporality — delta and cumulative

In the data model, a Sum consists of data points that have an AggregationTemporality (delta or cumulative), a monotonic flag, and start and end times. Delta reports the value of each non-overlapping time window, and cumulative reports the total from the start (usually the process start). A monotonic delta sum must not be negative, and a monotonic cumulative sum must not be smaller than the previous value.

The specification lists process restart detection, rate calculation, and push/pull methods as trade-offs between the two, and notes that OTLP supports both and can perform a Delta-to-Cumulative or Cumulative-to-Delta conversion when needed. A histogram also has a temporality; min and max are more useful in delta, and delta→cumulative conversion is possible but not the reverse. The concepts document also points out the relationship with cardinality — delta clears state every period and so counts only the combinations within one period, but cumulative keeps state, so once it hits the limit it keeps overflowing until the process restarts. A Gauge is a sampled value at a specific moment, so it has no temporality.

The fields of a log record

The log data model started from the requirement that "an existing log format must be mappable into this model without ambiguity," and it places commonly used fields as named top-level fields and the rest in Attributes. There are twelve top-level fields.

Field Meaning
Timestamp The time the event occurred (the source clock)
ObservedTimestamp The time the collection system observed it. For logs created in an SDK, the same as Timestamp
TraceId / SpanId / TraceFlags The identifiers and flags of W3C Trace Context. Attached to logs emitted during request handling
SeverityText The log level string from the source
SeverityNumber The normalized severity number
Body The body
Resource The entity that emitted the log
InstrumentationScope The scope that emitted the log (library or module)
Attributes Additional information
EventName A name indicating the kind of event

When mapping to a place that supports only one timestamp, use Timestamp if it exists, and otherwise ObservedTimestamp. SeverityNumber ranges from 1 to 24: 1–4 TRACE, 5–8 DEBUG, 9–12 INFO, 13–16 WARN, 17–20 ERROR, and 21–24 FATAL, with 0 meaning unspecified. As in the specification's example, 17 is a less severe error than 20. Events are a standardized form of this LogRecord, and the log semantic conventions are defined in the Event form.

The bridge API

The logs API states its audience in its first sentence — "It is provided for logging library authors to build log appenders, which use this API to connect existing logging libraries to the OpenTelemetry log data model." The structure is that you get a Logger from a LoggerProvider (with name, and optionally version, schema_url, and attributes), and the Logger Emits a LogRecord, and that is all. Emit accepts Timestamp, ObservedTimestamp, Context, SeverityNumber, SeverityText, Body, Attributes, and EventName, and if you do not pass a Context it uses the current Context — this is the principle by which TraceId and SpanId are attached to logs automatically. Enabled is an optimization you ask about first only when creating a LogRecord is expensive, and calling it is not required.

The logs signal overview divides collection into two approaches. One is where the Collector reads and parses logs written to files or standard output (it needs almost no application change, but parsing is hard), and the other is where you attach an appender and send directly over OTLP (it structures well and eliminates files, rotation, and parsing, but needs a destination that accepts OTLP). Either way, the application developer only has to configure the appender and the SDK at startup.

The schema URL

Semantic conventions evolve, and telemetry sources and consumers change at different speeds. To separate the three parties, the schema specification defines the following. A schema has a version (MAJOR.MINOR.PATCH), the conversions between versions (for example renaming an attribute) are specified explicitly in the schema file, and each version is identified by a unique Schema URL. The last path segment of the URL is the version, and what precedes it is the schema family. Once published, a schema file is immutable, so it can be cached permanently. The source (the instrumentation library) puts the schema URL into the telemetry it emits — the schema_url argument when you obtain a Tracer, Meter, or Logger is where it goes — and the consumer looks at the schema version it received and, if needed, converts it to the version it expects. The documentation's example is a backend that expects 1.1.0 renaming 1.2.0's deployment.environment to environment when storing it, and if the backend does not know the schema, the Collector's schema transform processor does it on its behalf. OpenTelemetry's own schemas are published under the /schemas/<version> path.

What it looks like in the field

One team recorded "the current number of active connections" with a Counter, so the graph only went up. It should go down when a connection closes, so an UpDownCounter was right, and in practice a callback that reads the value from the connection pool was more natural, so they switched to an Asynchronous UpDownCounter.

Another team said the metric values going to Prometheus and going to a vendor backend were different, and it turned out one was set to cumulative and the other to delta. Even for the same Counter, if the temporality differs, the interval that a single point's number represents differs.

What to check in the next quiz

The quiz asks about the reason for separating the API and SDK, the defaults of the Batching processor, the difference between synchronous and asynchronous instruments and their Context association, the meaning of delta and cumulative, LogRecord's Timestamp and ObservedTimestamp, the audience of the bridge API, and the role of the schema URL.