Skip to content

Commit f3dc1d5

Browse files
committed
Fix issue 2485 enable caching for get_logger calls
Cache one Logger object per Python logger name in LoggingHandler
1 parent 29c293f commit f3dc1d5

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import logging
2020
import threading
2121
import traceback
22+
from functools import lru_cache
2223
from os import environ
2324
from time import time_ns
2425
from typing import Any, Callable, Optional, Tuple, Union # noqa
@@ -448,9 +449,6 @@ def __init__(
448449
) -> None:
449450
super().__init__(level=level)
450451
self._logger_provider = logger_provider or get_logger_provider()
451-
self._logger = get_logger(
452-
__name__, logger_provider=self._logger_provider
453-
)
454452

455453
@staticmethod
456454
def _get_attributes(record: logging.LogRecord) -> Attributes:
@@ -530,6 +528,9 @@ def _translate(self, record: logging.LogRecord) -> LogRecord:
530528
"WARN" if record.levelname == "WARNING" else record.levelname
531529
)
532530

531+
logger = get_logger(
532+
record.name, logger_provider=self._logger_provider
533+
)
533534
return LogRecord(
534535
timestamp=timestamp,
535536
observed_timestamp=observered_timestamp,
@@ -539,7 +540,7 @@ def _translate(self, record: logging.LogRecord) -> LogRecord:
539540
severity_text=level_name,
540541
severity_number=severity_number,
541542
body=body,
542-
resource=self._logger.resource,
543+
resource=logger.resource,
543544
attributes=attributes,
544545
)
545546

@@ -549,15 +550,17 @@ def emit(self, record: logging.LogRecord) -> None:
549550
550551
The record is translated to OTel format, and then sent across the pipeline.
551552
"""
552-
if not isinstance(self._logger, NoOpLogger):
553-
self._logger.emit(self._translate(record))
553+
logger = get_logger(
554+
record.name, logger_provider=self._logger_provider
555+
)
556+
if not isinstance(logger, NoOpLogger):
557+
logger.emit(self._translate(record))
554558

555559
def flush(self) -> None:
556560
"""
557561
Flushes the logging output. Skip flushing if logger is NoOp.
558562
"""
559-
if not isinstance(self._logger, NoOpLogger):
560-
self._logger_provider.force_flush()
563+
self._logger_provider.force_flush()
561564

562565

563566
class Logger(APILogger):
@@ -618,6 +621,7 @@ def __init__(
618621
def resource(self):
619622
return self._resource
620623

624+
@lru_cache(maxsize=None)
621625
def get_logger(
622626
self,
623627
name: str,

opentelemetry-sdk/tests/logs/test_export.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def test_simple_log_record_processor_default_level(self):
7171
self.assertEqual(
7272
warning_log_record.severity_number, SeverityNumber.WARN
7373
)
74+
self.assertEqual(finished_logs[0].instrumentation_scope.name, "default_level")
7475

7576
def test_simple_log_record_processor_custom_level(self):
7677
exporter = InMemoryLogExporter()
@@ -104,6 +105,8 @@ def test_simple_log_record_processor_custom_level(self):
104105
self.assertEqual(
105106
fatal_log_record.severity_number, SeverityNumber.FATAL
106107
)
108+
self.assertEqual(finished_logs[0].instrumentation_scope.name, "custom_level")
109+
self.assertEqual(finished_logs[1].instrumentation_scope.name, "custom_level")
107110

108111
def test_simple_log_record_processor_trace_correlation(self):
109112
exporter = InMemoryLogExporter()
@@ -129,6 +132,7 @@ def test_simple_log_record_processor_trace_correlation(self):
129132
self.assertEqual(
130133
log_record.trace_flags, INVALID_SPAN_CONTEXT.trace_flags
131134
)
135+
self.assertEqual(finished_logs[0].instrumentation_scope.name, "trace_correlation")
132136
exporter.clear()
133137

134138
tracer = trace.TracerProvider().get_tracer(__name__)
@@ -140,6 +144,7 @@ def test_simple_log_record_processor_trace_correlation(self):
140144
self.assertEqual(log_record.body, "Critical message within span")
141145
self.assertEqual(log_record.severity_text, "CRITICAL")
142146
self.assertEqual(log_record.severity_number, SeverityNumber.FATAL)
147+
self.assertEqual(finished_logs[0].instrumentation_scope.name, "trace_correlation")
143148
span_context = span.get_span_context()
144149
self.assertEqual(log_record.trace_id, span_context.trace_id)
145150
self.assertEqual(log_record.span_id, span_context.span_id)
@@ -166,6 +171,7 @@ def test_simple_log_record_processor_shutdown(self):
166171
self.assertEqual(
167172
warning_log_record.severity_number, SeverityNumber.WARN
168173
)
174+
self.assertEqual(finished_logs[0].instrumentation_scope.name, "shutdown")
169175
exporter.clear()
170176
logger_provider.shutdown()
171177
with self.assertLogs(level=logging.WARNING):
@@ -206,6 +212,8 @@ def test_simple_log_record_processor_different_msg_types(self):
206212
for item in finished_logs
207213
]
208214
self.assertEqual(expected, emitted)
215+
for item in finished_logs:
216+
self.assertEqual(item.instrumentation_scope.name, "different_msg_types")
209217

210218

211219
class TestBatchLogRecordProcessor(ConcurrencyTestBase):
@@ -379,6 +387,8 @@ def test_shutdown(self):
379387
for item in finished_logs
380388
]
381389
self.assertEqual(expected, emitted)
390+
for item in finished_logs:
391+
self.assertEqual(item.instrumentation_scope.name, "shutdown")
382392

383393
def test_force_flush(self):
384394
exporter = InMemoryLogExporter()
@@ -398,6 +408,7 @@ def test_force_flush(self):
398408
log_record = finished_logs[0].log_record
399409
self.assertEqual(log_record.body, "Earth is burning")
400410
self.assertEqual(log_record.severity_number, SeverityNumber.FATAL)
411+
self.assertEqual(finished_logs[0].instrumentation_scope.name, "force_flush")
401412

402413
def test_log_record_processor_too_many_logs(self):
403414
exporter = InMemoryLogExporter()
@@ -416,6 +427,8 @@ def test_log_record_processor_too_many_logs(self):
416427
self.assertTrue(log_record_processor.force_flush())
417428
finised_logs = exporter.get_finished_logs()
418429
self.assertEqual(len(finised_logs), 1000)
430+
for item in finised_logs:
431+
self.assertEqual(item.instrumentation_scope.name, "many_logs")
419432

420433
def test_with_multiple_threads(self):
421434
exporter = InMemoryLogExporter()
@@ -443,6 +456,8 @@ def bulk_log_and_flush(num_logs):
443456

444457
finished_logs = exporter.get_finished_logs()
445458
self.assertEqual(len(finished_logs), 2415)
459+
for item in finished_logs:
460+
self.assertEqual(item.instrumentation_scope.name, "threads")
446461

447462
@unittest.skipUnless(
448463
hasattr(os, "fork"),

0 commit comments

Comments
 (0)