Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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,18 @@ 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))
attach(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