Skip to content

Commit 1d42539

Browse files
tm0nksfc-gh-jopel
authored andcommitted
Fix issue 2485 enable caching for get_logger calls
Cache one Logger object per Python logger name in LoggingHandler
1 parent cafd7f2 commit 1d42539

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

Diff for: opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import threading
2121
import traceback
2222
import warnings
23+
from functools import lru_cache
2324
from os import environ
2425
from time import time_ns
2526
from typing import Any, Callable, Optional, Tuple, Union # noqa
@@ -471,9 +472,6 @@ def __init__(
471472
) -> None:
472473
super().__init__(level=level)
473474
self._logger_provider = logger_provider or get_logger_provider()
474-
self._logger = get_logger(
475-
__name__, logger_provider=self._logger_provider
476-
)
477475

478476
@staticmethod
479477
def _get_attributes(record: logging.LogRecord) -> Attributes:
@@ -558,6 +556,7 @@ def _translate(self, record: logging.LogRecord) -> LogRecord:
558556
"WARN" if record.levelname == "WARNING" else record.levelname
559557
)
560558

559+
logger = get_logger(record.name, logger_provider=self._logger_provider)
561560
return LogRecord(
562561
timestamp=timestamp,
563562
observed_timestamp=observered_timestamp,
@@ -567,7 +566,7 @@ def _translate(self, record: logging.LogRecord) -> LogRecord:
567566
severity_text=level_name,
568567
severity_number=severity_number,
569568
body=body,
570-
resource=self._logger.resource,
569+
resource=logger.resource,
571570
attributes=attributes,
572571
)
573572

@@ -577,15 +576,15 @@ def emit(self, record: logging.LogRecord) -> None:
577576
578577
The record is translated to OTel format, and then sent across the pipeline.
579578
"""
580-
if not isinstance(self._logger, NoOpLogger):
581-
self._logger.emit(self._translate(record))
579+
logger = get_logger(record.name, logger_provider=self._logger_provider)
580+
if not isinstance(logger, NoOpLogger):
581+
logger.emit(self._translate(record))
582582

583583
def flush(self) -> None:
584584
"""
585585
Flushes the logging output. Skip flushing if logger is NoOp.
586586
"""
587-
if not isinstance(self._logger, NoOpLogger):
588-
self._logger_provider.force_flush()
587+
self._logger_provider.force_flush()
589588

590589

591590
class Logger(APILogger):
@@ -647,6 +646,7 @@ def __init__(
647646
def resource(self):
648647
return self._resource
649648

649+
@lru_cache(maxsize=None)
650650
def get_logger(
651651
self,
652652
name: str,

Diff for: opentelemetry-sdk/tests/logs/test_export.py

+32
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ def test_simple_log_record_processor_default_level(self):
7171
self.assertEqual(
7272
warning_log_record.severity_number, SeverityNumber.WARN
7373
)
74+
self.assertEqual(
75+
finished_logs[0].instrumentation_scope.name, "default_level"
76+
)
7477

7578
def test_simple_log_record_processor_custom_level(self):
7679
exporter = InMemoryLogExporter()
@@ -104,6 +107,12 @@ def test_simple_log_record_processor_custom_level(self):
104107
self.assertEqual(
105108
fatal_log_record.severity_number, SeverityNumber.FATAL
106109
)
110+
self.assertEqual(
111+
finished_logs[0].instrumentation_scope.name, "custom_level"
112+
)
113+
self.assertEqual(
114+
finished_logs[1].instrumentation_scope.name, "custom_level"
115+
)
107116

108117
def test_simple_log_record_processor_trace_correlation(self):
109118
exporter = InMemoryLogExporter()
@@ -129,6 +138,9 @@ def test_simple_log_record_processor_trace_correlation(self):
129138
self.assertEqual(
130139
log_record.trace_flags, INVALID_SPAN_CONTEXT.trace_flags
131140
)
141+
self.assertEqual(
142+
finished_logs[0].instrumentation_scope.name, "trace_correlation"
143+
)
132144
exporter.clear()
133145

134146
tracer = trace.TracerProvider().get_tracer(__name__)
@@ -140,6 +152,10 @@ def test_simple_log_record_processor_trace_correlation(self):
140152
self.assertEqual(log_record.body, "Critical message within span")
141153
self.assertEqual(log_record.severity_text, "CRITICAL")
142154
self.assertEqual(log_record.severity_number, SeverityNumber.FATAL)
155+
self.assertEqual(
156+
finished_logs[0].instrumentation_scope.name,
157+
"trace_correlation",
158+
)
143159
span_context = span.get_span_context()
144160
self.assertEqual(log_record.trace_id, span_context.trace_id)
145161
self.assertEqual(log_record.span_id, span_context.span_id)
@@ -166,6 +182,9 @@ def test_simple_log_record_processor_shutdown(self):
166182
self.assertEqual(
167183
warning_log_record.severity_number, SeverityNumber.WARN
168184
)
185+
self.assertEqual(
186+
finished_logs[0].instrumentation_scope.name, "shutdown"
187+
)
169188
exporter.clear()
170189
logger_provider.shutdown()
171190
with self.assertLogs(level=logging.WARNING):
@@ -206,6 +225,10 @@ def test_simple_log_record_processor_different_msg_types(self):
206225
for item in finished_logs
207226
]
208227
self.assertEqual(expected, emitted)
228+
for item in finished_logs:
229+
self.assertEqual(
230+
item.instrumentation_scope.name, "different_msg_types"
231+
)
209232

210233
def test_simple_log_record_processor_different_msg_types_with_formatter(
211234
self,
@@ -428,6 +451,8 @@ def test_shutdown(self):
428451
for item in finished_logs
429452
]
430453
self.assertEqual(expected, emitted)
454+
for item in finished_logs:
455+
self.assertEqual(item.instrumentation_scope.name, "shutdown")
431456

432457
def test_force_flush(self):
433458
exporter = InMemoryLogExporter()
@@ -447,6 +472,9 @@ def test_force_flush(self):
447472
log_record = finished_logs[0].log_record
448473
self.assertEqual(log_record.body, "Earth is burning")
449474
self.assertEqual(log_record.severity_number, SeverityNumber.FATAL)
475+
self.assertEqual(
476+
finished_logs[0].instrumentation_scope.name, "force_flush"
477+
)
450478

451479
def test_log_record_processor_too_many_logs(self):
452480
exporter = InMemoryLogExporter()
@@ -465,6 +493,8 @@ def test_log_record_processor_too_many_logs(self):
465493
self.assertTrue(log_record_processor.force_flush())
466494
finised_logs = exporter.get_finished_logs()
467495
self.assertEqual(len(finised_logs), 1000)
496+
for item in finised_logs:
497+
self.assertEqual(item.instrumentation_scope.name, "many_logs")
468498

469499
def test_with_multiple_threads(self):
470500
exporter = InMemoryLogExporter()
@@ -492,6 +522,8 @@ def bulk_log_and_flush(num_logs):
492522

493523
finished_logs = exporter.get_finished_logs()
494524
self.assertEqual(len(finished_logs), 2415)
525+
for item in finished_logs:
526+
self.assertEqual(item.instrumentation_scope.name, "threads")
495527

496528
@unittest.skipUnless(
497529
hasattr(os, "fork"),

0 commit comments

Comments
 (0)