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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Silence events API warnings for internal users
([#4847](https://github.com/open-telemetry/opentelemetry-python/pull/4847))
- Prevent possible endless recursion from happening in `SimpleLogRecordProcessor.on_emit`,
([#4799](https://github.com/open-telemetry/opentelemetry-python/pull/4799)).
([#4799](https://github.com/open-telemetry/opentelemetry-python/pull/4799)) and ([#4867](https://github.com/open-telemetry/opentelemetry-python/pull/4867)).

## Version 1.39.0/0.60b0 (2025-12-03)

Expand Down
1 change: 1 addition & 0 deletions opentelemetry-api/src/opentelemetry/context/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def detach(token: Token[Context]) -> None:
# FIXME This is a temporary location for the suppress instrumentation key.
# Once the decision around how to suppress instrumentation is made in the
# spec, this key should be moved accordingly.
_ON_EMIT_RECURSION_COUNT_KEY = create_key("on_emit_recursion_count")
_SUPPRESS_INSTRUMENTATION_KEY = create_key("suppress_instrumentation")
_SUPPRESS_HTTP_INSTRUMENTATION_KEY = create_key(
"suppress_http_instrumentation"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@
import enum
import logging
import sys
import traceback
from os import environ, linesep
from typing import IO, Callable, Optional, Sequence

from typing_extensions import deprecated

from opentelemetry.context import (
_ON_EMIT_RECURSION_COUNT_KEY,
_SUPPRESS_INSTRUMENTATION_KEY,
attach,
detach,
get_value,
set_value,
)
from opentelemetry.sdk._logs import (
Expand Down Expand Up @@ -150,28 +151,23 @@ def __init__(self, exporter: LogRecordExporter):

def on_emit(self, log_record: ReadWriteLogRecord):
# Prevent entering a recursive loop.
if (
sum(
item.name == "on_emit"
and (
item.filename.endswith("export/__init__.py")
or item.filename.endswith(
r"export\__init__.py"
) # backward slash on windows..
)
for item in traceback.extract_stack()
)
# Recursive depth of 3 is sort of arbitrary. It's possible that an Exporter.export call
# emits a log which returns us to this function, but when we call Exporter.export again the log
# is no longer emitted and we exit this recursive loop naturally, a depth of >3 allows 3
# recursive log calls but exits after because it's likely endless.
> 3
):
cnt = get_value(_ON_EMIT_RECURSION_COUNT_KEY) or 0
# Recursive depth of 3 is sort of arbitrary. It's possible that an Exporter.export call
# emits a log which returns us to this function, but when we call Exporter.export again the log
# is no longer emitted and we exit this recursive loop naturally, a depth of >3 allows 3
# recursive log calls but exits after because it's likely endless.
if cnt > 3: # pyright: ignore[reportOperatorIssue]
_propagate_false_logger.warning(
"SimpleLogRecordProcessor.on_emit has entered a recursive loop. Dropping log and exiting the loop."
)
return
token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))
token = attach(
set_value(
_SUPPRESS_INSTRUMENTATION_KEY,
True,
set_value(_ON_EMIT_RECURSION_COUNT_KEY, cnt + 1), # pyright: ignore[reportOperatorIssue]
)
)
try:
if self._shutdown:
_logger.warning("Processor is already shutdown, ignoring call")
Expand Down
Loading