Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/fixed/typing-tapir.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix OpenTelemetry logger attribute typing and logger-provider test collection with OpenTelemetry 1.45 and newer by accepting string-keyed mappings without restricting attribute value types.
12 changes: 5 additions & 7 deletions temporalio/contrib/opentelemetry/_logger_provider.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any
from collections.abc import Mapping
from typing import Any

# The OpenTelemetry Logs API specification is stable, but opentelemetry-python
# exposes the logs bridge API only under the private opentelemetry._logs
Expand All @@ -13,11 +14,6 @@

from temporalio import workflow

if TYPE_CHECKING:
# _ExtendedAttributes is the annotation OpenTelemetry's own public
# get_logger signature uses; there is no public alias.
from opentelemetry.util.types import _ExtendedAttributes


def _skip_emitting() -> bool:
# in_workflow() must be evaluated first: is_replaying_history_events()
Expand Down Expand Up @@ -123,7 +119,7 @@ def get_logger(
name: str,
version: str | None = None,
schema_url: str | None = None,
attributes: _ExtendedAttributes | None = None,
attributes: Mapping[str, Any] | None = None,
) -> Logger:
"""Get a replay-safe logger from the underlying provider.

Expand All @@ -132,6 +128,8 @@ def get_logger(
version: The version string of the instrumenting library.
schema_url: The schema URL for the logger.
attributes: Instrumentation scope attributes for the logger.
Values are typed permissively to support different OpenTelemetry
attribute types across supported versions.

Returns:
A replay-safe logger instance.
Expand Down
18 changes: 12 additions & 6 deletions tests/contrib/opentelemetry/test_logger_provider.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""Unit tests for ReplaySafeLoggerProvider."""

from collections.abc import Iterator
from collections.abc import Iterator, Mapping
from contextlib import contextmanager
from typing import Any
from unittest.mock import patch

import pytest
from opentelemetry._logs import (
Logger,
LoggerProvider,
Expand All @@ -17,7 +18,6 @@
InMemoryLogRecordExporter,
SimpleLogRecordProcessor,
)
from opentelemetry.util.types import _ExtendedAttributes

from temporalio import workflow
from temporalio.contrib.opentelemetry import ReplaySafeLoggerProvider
Expand Down Expand Up @@ -45,7 +45,13 @@ def test_replay_safe_logger_provider_emit_passes_through_outside_workflow():
assert records[1].attributes and dict(records[1].attributes) == {"attr": "val"}


def test_replay_safe_logger_provider_delegates_get_logger_arguments():
@pytest.mark.parametrize(
"attributes",
[None, {"attr": "val"}, {"nested": {"values": [1, b"bytes", None]}}],
)
def test_replay_safe_logger_provider_delegates_get_logger_arguments(
attributes: Mapping[str, Any] | None,
):
class RecordingLoggerProvider(LoggerProvider):
def __init__(self) -> None:
self.calls: list[tuple] = []
Expand All @@ -56,7 +62,7 @@ def get_logger(
name: str,
version: str | None = None,
schema_url: str | None = None,
attributes: _ExtendedAttributes | None = None,
attributes: Mapping[str, Any] | None = None,
) -> Logger:
self.calls.append((name, version, schema_url, attributes))
return self._inner.get_logger(name, version, schema_url, attributes)
Expand All @@ -67,11 +73,11 @@ def get_logger(
"test-logger",
version="1.2.3",
schema_url="https://example.com/schema",
attributes={"attr": "val"},
attributes=attributes,
)

assert inner_provider.calls == [
("test-logger", "1.2.3", "https://example.com/schema", {"attr": "val"})
("test-logger", "1.2.3", "https://example.com/schema", attributes)
]


Expand Down
Loading