Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
3eb0b56
Document opentelemetry.sdk.version
ocelotl Oct 31, 2026
f7c87b2
Document opentelemetry.sdk._configuration
ocelotl Oct 31, 2026
e66b252
Document opentelemetry.sdk._logs
ocelotl Oct 31, 2026
2ce8b9d
Document opentelemetry.sdk._logs._internal
ocelotl Oct 31, 2026
0e65d60
Document opentelemetry.sdk._logs._internal._exceptions
ocelotl Oct 31, 2026
0f5e721
Document opentelemetry.sdk._logs._internal._logger_metrics
ocelotl Oct 31, 2026
6195345
Document opentelemetry.sdk._logs._internal.export
ocelotl Oct 31, 2026
283f2ff
Document opentelemetry.sdk._logs._internal.export.in_memory_log_exporter
ocelotl Oct 31, 2026
d80ccff
Document opentelemetry.sdk._logs.export
ocelotl Oct 31, 2026
f95e625
Document opentelemetry.sdk._shared_internal
ocelotl Oct 31, 2026
d89f639
Document opentelemetry.sdk._shared_internal._processor_metrics
ocelotl Oct 31, 2026
1d1b18e
Document opentelemetry.sdk.environment_variables
ocelotl Oct 31, 2026
1363170
Document opentelemetry.sdk.environment_variables._internal
ocelotl Oct 31, 2026
3dcec0b
Document opentelemetry.sdk.error_handler
ocelotl Oct 31, 2026
1bd5823
Document opentelemetry.sdk.metrics
ocelotl Oct 31, 2026
1c9cd99
Document opentelemetry.sdk.metrics._internal
ocelotl Oct 31, 2026
7224904
Document opentelemetry.sdk.metrics._internal._view_instrument_match
ocelotl Oct 31, 2026
29fc9ba
Document opentelemetry.sdk.metrics._internal.aggregation
ocelotl Oct 31, 2026
dc3c024
Document opentelemetry.sdk.metrics._internal.exceptions
ocelotl Oct 31, 2026
1baf652
Document opentelemetry.sdk.metrics._internal.exemplar
ocelotl Oct 31, 2026
9940f7c
Document opentelemetry.sdk.metrics._internal.exemplar.exemplar
ocelotl Oct 31, 2026
a4d2514
Document opentelemetry.sdk.metrics._internal.exemplar.exemplar_filter
ocelotl Oct 31, 2026
92d17ac
Document opentelemetry.sdk.metrics._internal.exemplar.exemplar_reservoir
ocelotl Oct 31, 2026
9663c31
Document opentelemetry.sdk.metrics._internal.exponential_histogram
ocelotl Oct 31, 2026
79da462
Document the exponential histogram buckets
ocelotl Oct 31, 2026
207e023
Document the exponential histogram mapping interface
ocelotl Oct 31, 2026
3e066bb
Document the exponential histogram mapping errors
ocelotl Oct 31, 2026
b8129df
Document the exponential histogram exponent mapping
ocelotl Oct 31, 2026
298ee74
Document the IEEE 754 field readers
ocelotl Oct 31, 2026
9400ed3
Document the exponential histogram logarithm mapping
ocelotl Oct 31, 2026
56f1ffa
Document opentelemetry.sdk.metrics._internal.export
ocelotl Oct 31, 2026
802937e
Document the metrics a metric reader emits about itself
ocelotl Oct 31, 2026
4776752
Document opentelemetry.sdk.metrics._internal.instrument
ocelotl Oct 31, 2026
c8833e8
Document opentelemetry.sdk.metrics._internal.measurement
ocelotl Oct 31, 2026
40d2540
Document opentelemetry.sdk.metrics._internal.measurement_consumer
ocelotl Oct 31, 2026
367253b
Document opentelemetry.sdk.metrics._internal.metric_reader_storage
ocelotl Oct 31, 2026
8c47ff8
Document opentelemetry.sdk.metrics._internal.point
ocelotl Oct 31, 2026
7acc20d
Document opentelemetry.sdk.metrics._internal.sdk_configuration
ocelotl Oct 31, 2026
0f3557b
Document opentelemetry.sdk.metrics._internal.view
ocelotl Oct 31, 2026
a89e5a8
Document opentelemetry.sdk.metrics.export
ocelotl Oct 31, 2026
9bef43b
Document opentelemetry.sdk.metrics.view
ocelotl Oct 31, 2026
a73f67c
Document opentelemetry.sdk.resources
ocelotl Oct 31, 2026
3155baf
Document opentelemetry.sdk.trace
ocelotl Oct 31, 2026
650ec23
Document opentelemetry.sdk.trace._sampling_experimental
ocelotl Oct 31, 2026
b1d1d21
Document opentelemetry.sdk.trace._sampling_experimental._always_off
ocelotl Oct 31, 2026
5601317
Document opentelemetry.sdk.trace._sampling_experimental._always_on
ocelotl Oct 31, 2026
e8a98d0
Document opentelemetry.sdk.trace._sampling_experimental._composable
ocelotl Oct 31, 2026
131f1a7
Document the parent threshold composable sampler
ocelotl Oct 31, 2026
1ec7c1d
Document opentelemetry.sdk.trace._sampling_experimental._rule_based
ocelotl Oct 31, 2026
6e59e57
Document opentelemetry.sdk.trace._sampling_experimental._sampler
ocelotl Oct 31, 2026
f301196
Document opentelemetry.sdk.trace._sampling_experimental._trace_state
ocelotl Oct 31, 2026
1f212c7
Document opentelemetry.sdk.trace._sampling_experimental._traceid_ratio
ocelotl Oct 31, 2026
bb07a9e
Document opentelemetry.sdk.trace._sampling_experimental._util
ocelotl Oct 31, 2026
6caf874
Document opentelemetry.sdk.trace._tracer_metrics
ocelotl Oct 31, 2026
871c217
Document opentelemetry.sdk.trace.export
ocelotl Oct 31, 2026
a489696
Document opentelemetry.sdk.trace.export.in_memory_span_exporter
ocelotl Oct 31, 2026
8b182ad
Document opentelemetry.sdk.trace.id_generator
ocelotl Oct 31, 2026
759528b
Document opentelemetry.sdk.trace.sampling
ocelotl Oct 31, 2026
4aebece
Document opentelemetry.sdk.util
ocelotl Oct 31, 2026
9535dbe
Document opentelemetry.sdk.util._configurator
ocelotl Oct 31, 2026
5dee3dc
Document opentelemetry.sdk.util.instrumentation
ocelotl Oct 31, 2026
e005bbe
Ignore seven unresolvable targets in the nitpicky docs build
ocelotl Oct 31, 2026
5345df0
Add the changelog fragment
ocelotl Oct 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changelog/5869.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`opentelemetry-sdk`: document every hand-written module, class and callable
28 changes: 28 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,34 @@
"py:class",
"opentelemetry.sdk.metrics._internal.instrument._Asynchronous",
),
(
"py:class",
"opentelemetry.sdk.trace._TracerConfig",
),
(
"py:class",
"opentelemetry.sdk.metrics._internal._MeterConfig",
),
(
"py:class",
"opentelemetry.sdk.metrics._internal._ProxyMeterConfig",
),
(
"py:class",
"opentelemetry.sdk.metrics._internal.measurement_consumer.MeasurementConsumer",
),
(
"py:class",
"opentelemetry.sdk._logs._internal._LoggerConfig",
),
(
"py:class",
"opentelemetry.sdk._logs._internal._logger_metrics.LoggerMetricsT",
),
(
"py:class",
"opentelemetry.semconv._incubating.attributes.otel_attributes.OtelComponentTypeValues",
),
# Even if wrapt is added to intersphinx_mapping, sphinx keeps failing
# with "class reference target not found: ObjectProxy".
("py:class", "ObjectProxy"),
Expand Down
511 changes: 507 additions & 4 deletions opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
"""Public names of the OpenTelemetry logs SDK.

This module re-exports the two log record wrappers, the attribute limits, the
log record processor interface with its two multiplexing implementations, the
``logging`` module bridge and ``LoggerProvider``. The implementation of all of
them lives in ``opentelemetry.sdk._logs._internal``. Import from here instead:
the layout of the private package may change between releases, while the names
listed in ``__all__`` are the ones the SDK supports.

``LogDroppedAttributesWarning`` and ``LogLimits`` are deprecated aliases kept
for callers written against the older spelling.
"""

from opentelemetry.sdk._logs._internal import (
ConcurrentMultiLogRecordProcessor,
Expand Down
941 changes: 934 additions & 7 deletions opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py

Large diffs are not rendered by default.

124 changes: 124 additions & 0 deletions opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
"""Turning an exception attached to a log record into attributes.

``LogRecord`` carries an ``exception`` field holding a live ``BaseException``.
Nothing downstream can serialise that, so before a record reaches a processor
the SDK derives the three ``exception.*`` semantic convention attributes from
it. The helpers here do that derivation in the three shapes ``Logger.emit``
needs: build a fresh record, copy an existing one, or edit one in place.

An attribute the caller set by hand always wins over the derived value, in
every one of those shapes.
"""

from __future__ import annotations

import traceback
Expand All @@ -13,6 +25,23 @@
def _get_exception_attributes(
exception: BaseException,
) -> dict[str, AnyValue]:
"""Derive the three ``exception.*`` attributes from an exception.

The type is qualified with the defining module, so a ``ValueError`` comes
out as ``ValueError`` while a custom class comes out as
``mypackage.mymodule.MyError``. Builtins are left unqualified.

Args:
exception: The exception to describe. Its ``__traceback__`` supplies
the stack trace, and an exception that was never raised has none,
which yields a one-line trace holding only the exception itself.

Returns:
A mapping with ``exception.type``, ``exception.message`` and
``exception.stacktrace``. The message is ``str(exception)``, which is
the empty string for an exception constructed with no arguments. All
three keys are always present.
"""
stacktrace = "".join(traceback.format_exception(type(exception), value=exception, tb=exception.__traceback__))
module = type(exception).__module__
qualname = type(exception).__qualname__
Expand All @@ -28,6 +57,29 @@ def _get_attributes_with_exception(
attributes: Attributes,
exception: BaseException | None,
) -> Attributes:
"""Merge the derived exception attributes under the caller's attributes.

A key the caller already set is never overwritten, so passing
``exception.message`` explicitly keeps that text and discards the one
derived from the exception.

Args:
attributes: The attributes already on the record. ``None`` is treated
as an empty mapping.
exception: The exception to describe, or ``None`` to leave
``attributes`` untouched.

Returns:
``attributes`` itself, unchanged and possibly ``None``, when
``exception`` is ``None``. A new ``BoundedAttributes`` carrying the
same ``maxlen`` and ``max_value_len`` when ``attributes`` was one,
which means the exception attributes are themselves subject to those
limits and can be dropped or truncated. Its ``dropped`` count starts
from the input's and is then raised by however many of the three
exception attributes the count limit refused, so it is at least the
input's count rather than equal to it. A plain ``dict`` otherwise.
The input mapping is never modified.
"""
if exception is None:
return attributes

Expand Down Expand Up @@ -58,6 +110,21 @@ def _copy_log_record(
record: LogRecord,
attributes: Attributes,
) -> LogRecord:
"""Shallow-copy a log record, swapping in a different attribute mapping.

Every other field is carried over by reference. ``trace_id``, ``span_id``
and ``trace_flags`` are reassigned after construction because the
``LogRecord`` constructor otherwise re-derives them from ``context``, which
would lose the values a caller set by hand.

Args:
record: The record to copy. It is not modified.
attributes: The attribute mapping the copy gets. Passing the mapping of
``record`` makes the two records share it.

Returns:
The new record.
"""
copied_record = LogRecord(
timestamp=record.timestamp,
observed_timestamp=record.observed_timestamp,
Expand All @@ -76,13 +143,39 @@ def _copy_log_record(


def _copy_log_record_with_exception(record: LogRecord) -> LogRecord:
"""Copy a log record with its exception rendered into attributes.

``Logger.emit`` uses this when the caller hands it a record it does not
own, so that the caller's record keeps the attribute mapping it had.

Args:
record: The record to copy. It is not modified, including its
attributes.

Returns:
A new record whose attributes carry ``exception.type``,
``exception.message`` and ``exception.stacktrace``. When
``record.exception`` is ``None`` the copy shares the original attribute
mapping rather than getting one of its own.
"""
return _copy_log_record(
record,
_get_attributes_with_exception(record.attributes, record.exception),
)


def _set_log_record_exception_attributes(record: LogRecord) -> None:
"""Render a log record's exception into its attributes, in place.

``Logger.emit`` uses this on a ``ReadWriteLogRecord``, which the SDK built
itself and is free to edit. The attribute mapping is replaced rather than
added to, so a ``BoundedAttributes`` mapping is swapped for a new one that
inherits its limits and its dropped count.

Args:
record: The record to edit. Nothing happens when its ``exception`` is
``None``.
"""
record.attributes = _get_attributes_with_exception(
record.attributes,
record.exception,
Expand All @@ -101,6 +194,37 @@ def _create_log_record_with_exception(
event_name: str | None = None,
exception: BaseException | None = None,
) -> LogRecord:
"""Build a log record from loose arguments, folding in an exception.

``Logger.emit`` uses this on the path where the caller passed individual
keyword arguments instead of a ready-made record.

Args:
timestamp: When the event happened, in nanoseconds since the Unix
epoch. ``None`` leaves the field unset, and a consumer is then
expected to fall back to ``observed_timestamp``.
observed_timestamp: When the SDK saw the event, in nanoseconds since
the Unix epoch. ``None`` makes ``LogRecord`` fill it with the
current time.
context: The context to take the trace id, span id and trace flags
from. ``None`` makes ``LogRecord`` use the current context.
severity_number: The severity as an ``opentelemetry._logs``
``SeverityNumber``, or ``None`` to leave it unset.
severity_text: The original severity label of the logging system the
record came from, or ``None``.
body: The payload of the event. Any attribute value type is accepted,
including a mapping or a sequence.
attributes: Attributes to attach. A key given here survives even when
the derived exception attributes use the same key.
event_name: The name identifying the class of event, or ``None`` for an
unnamed log record.
exception: The exception to describe in ``exception.*`` attributes. It
is also stored on the returned record, so the field still holds the
live exception object afterwards.

Returns:
The new record.
"""
return LogRecord(
timestamp=timestamp,
observed_timestamp=observed_timestamp,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
"""Self-observability counters for the logs SDK.

Holds the one metric the ``Logger`` records about itself, the count of log
records it has created, and a do-nothing stand-in used when self-observability
is switched off. ``Logger.emit`` calls ``emit_log`` once per record, so the
stand-in exists to keep that call cheap in the default configuration.
"""

from typing import Protocol

Expand All @@ -10,27 +17,78 @@


class LoggerMetricsT(Protocol):
def emit_log(self) -> None: ...
"""What ``Logger`` requires of the object it reports its own counts to."""

def emit_log(self) -> None:
"""Record that one log record has been created."""


class NoOpLoggerMetrics:
"""Implementation of ``LoggerMetricsT`` that records nothing.

Used when ``OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED`` is not set to true,
which is the default. No instrument is created, so no meter provider is
touched.
"""

def emit_log(self) -> None:
pass
"""Do nothing.

Present so that ``Logger`` can call it unconditionally instead of
testing whether self-observability is switched on.
"""


class LoggerMetrics:
"""Implementation of ``LoggerMetricsT`` backed by a real counter.

Creates the ``otel.sdk.log.created`` counter on a meter named
``opentelemetry-sdk`` when it is built, so the instrument exists even
before the first log record is emitted.

Args:
meter_provider: The provider to obtain the meter from. Pointing it at
the same provider that exports application metrics is what makes
these counts show up alongside them.
"""

def __init__(self, meter_provider: metrics_api.MeterProvider) -> None:
"""Build the instance and create the counter.

Every parameter is documented on the class itself, since that is the
form the API reference renders.
"""
meter = meter_provider.get_meter("opentelemetry-sdk")
self._created_logs = create_otel_sdk_log_created(meter)

def emit_log(self) -> None:
"""Add one to the ``otel.sdk.log.created`` counter.

Counts records the ``Logger`` accepted for processing. A record the
processors later drop, because the queue was full or the processor was
already shut down, has still been counted here.
"""
self._created_logs.add(1)


def create_logger_metrics(
meter_provider: metrics_api.MeterProvider,
enabled: bool,
) -> LoggerMetricsT:
"""Pick the recording or the do-nothing implementation.

Args:
meter_provider: The provider the counter is created on. Ignored when
``enabled`` is false, so passing a provider costs nothing in the
default configuration.
enabled: Whether to record at all. ``LoggerProvider`` passes the parsed
value of ``OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED``.

Returns:
A ``LoggerMetrics`` when ``enabled`` is true, otherwise a
``NoOpLoggerMetrics``. The choice is made once, at ``LoggerProvider``
construction, and cannot be changed afterwards.
"""
if not enabled:
return NoOpLoggerMetrics()

Expand Down
Loading
Loading