Skip to content

Commit b47ca63

Browse files
committed
Add support for log formatting
1 parent ea36c5d commit b47ca63

File tree

4 files changed

+89
-5
lines changed

4 files changed

+89
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
- sdk: Add support for log formatting
11+
([#4137](https://github.com/open-telemetry/opentelemetry-python/pull/4166))
1012
- Implementation of Events API
1113
([#4054](https://github.com/open-telemetry/opentelemetry-python/pull/4054))
1214
- Make log sdk add `exception.message` to logRecord for exceptions whose argument

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -544,10 +544,13 @@ def _translate(self, record: logging.LogRecord) -> LogRecord:
544544
# output format. Therefore, this change is considered a breaking
545545
# change and needs to be upgraded at an appropriate time.
546546
severity_number = std_to_otel(record.levelno)
547-
if isinstance(record.msg, str) and record.args:
548-
body = record.msg % record.args
547+
if self.formatter:
548+
body = self.format(record)
549549
else:
550-
body = record.msg
550+
if isinstance(record.msg, str) and record.args:
551+
body = record.msg % record.args
552+
else:
553+
body = record.msg
551554

552555
# related to https://github.com/open-telemetry/opentelemetry-python/issues/3548
553556
# Severity Text = WARN as defined in https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#displaying-severity.

opentelemetry-sdk/tests/logs/test_export.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,45 @@ def test_simple_log_record_processor_different_msg_types(self):
207207
]
208208
self.assertEqual(expected, emitted)
209209

210+
def test_simple_log_record_processor_different_msg_types_with_formatter(self):
211+
self.maxDiff = None
212+
exporter = InMemoryLogExporter()
213+
log_record_processor = BatchLogRecordProcessor(exporter)
214+
215+
provider = LoggerProvider()
216+
provider.add_log_record_processor(log_record_processor)
217+
218+
logger = logging.getLogger("different_msg_types")
219+
handler = LoggingHandler(logger_provider=provider)
220+
handler.setFormatter(logging.Formatter(
221+
"%(name)s - %(levelname)s - %(message)s"
222+
))
223+
logger.addHandler(handler)
224+
225+
logger.warning("warning message: %s", "possible upcoming heatwave")
226+
logger.error("Very high rise in temperatures across the globe")
227+
logger.critical("Temperature hits high 420 C in Hyderabad")
228+
logger.warning(["list", "of", "strings"])
229+
logger.error({"key": "value"})
230+
log_record_processor.shutdown()
231+
232+
finished_logs = exporter.get_finished_logs()
233+
expected = [
234+
("different_msg_types - WARNING - warning message: possible upcoming heatwave", "WARN"),
235+
("different_msg_types - ERROR - Very high rise in temperatures across the globe", "ERROR"),
236+
(
237+
"different_msg_types - CRITICAL - Temperature hits high 420 C in Hyderabad",
238+
"CRITICAL",
239+
),
240+
("different_msg_types - WARNING - ['list', 'of', 'strings']", "WARN"),
241+
("different_msg_types - ERROR - {'key': 'value'}", "ERROR"),
242+
]
243+
emitted = [
244+
(item.log_record.body, item.log_record.severity_text)
245+
for item in finished_logs
246+
]
247+
self.assertEqual(expected, emitted)
248+
210249

211250
class TestBatchLogRecordProcessor(ConcurrencyTestBase):
212251
def test_emit_call_log_record(self):

opentelemetry-sdk/tests/logs/test_handler.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414
import logging
1515
import unittest
16-
from unittest.mock import Mock
16+
from unittest.mock import Mock, MagicMock
1717

1818
from opentelemetry._logs import NoOpLoggerProvider, SeverityNumber
1919
from opentelemetry._logs import get_logger as APIGetLogger
@@ -242,13 +242,53 @@ def test_log_record_trace_correlation(self):
242242
self.assertEqual(log_record.span_id, span_context.span_id)
243243
self.assertEqual(log_record.trace_flags, span_context.trace_flags)
244244

245+
def test_warning_without_formatter(self):
246+
processor, logger = set_up_test_logging(logging.WARNING)
247+
logger.warning("Test message")
248+
249+
log_record = processor.get_log_record(0)
250+
self.assertEqual(log_record.body, "Test message")
251+
252+
def test_exception_without_formatter(self):
253+
processor, logger = set_up_test_logging(logging.WARNING)
254+
logger.exception("Test exception")
255+
256+
log_record = processor.get_log_record(0)
257+
self.assertEqual(log_record.body, "Test exception")
258+
259+
def test_warning_with_formatter(self):
260+
processor, logger = set_up_test_logging(
261+
logging.WARNING,
262+
formatter=logging.Formatter(
263+
"%(name)s - %(levelname)s - %(message)s"
264+
),
265+
)
266+
logger.warning("Test message")
267+
268+
log_record = processor.get_log_record(0)
269+
self.assertEqual(log_record.body, "foo - WARNING - Test message")
270+
271+
def test_log_body_is_always_string_with_formatter(self):
272+
processor, logger = set_up_test_logging(
273+
logging.WARNING,
274+
formatter=logging.Formatter(
275+
"%(name)s - %(levelname)s - %(message)s"
276+
),
277+
)
278+
logger.warning(["something", "of", "note"])
279+
280+
log_record = processor.get_log_record(0)
281+
self.assertIsInstance(log_record.body, str)
282+
245283

246-
def set_up_test_logging(level):
284+
def set_up_test_logging(level, formatter=None):
247285
logger_provider = LoggerProvider()
248286
processor = FakeProcessor()
249287
logger_provider.add_log_record_processor(processor)
250288
logger = logging.getLogger("foo")
251289
handler = LoggingHandler(level=level, logger_provider=logger_provider)
290+
if formatter:
291+
handler.setFormatter(formatter)
252292
logger.addHandler(handler)
253293
return processor, logger
254294

0 commit comments

Comments
 (0)