Skip to content

Commit

Permalink
Add log formatting support (open-telemetry#4166)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremydvoss authored Sep 4, 2024
1 parent 47a2504 commit e6486be
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- sdk: Add support for log formatting
([#4137](https://github.com/open-telemetry/opentelemetry-python/pull/4166))

## Version 1.27.0/0.48b0 (2024-08-28)

- Implementation of Events API
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,10 +544,13 @@ def _translate(self, record: logging.LogRecord) -> LogRecord:
# output format. Therefore, this change is considered a breaking
# change and needs to be upgraded at an appropriate time.
severity_number = std_to_otel(record.levelno)
if isinstance(record.msg, str) and record.args:
body = record.msg % record.args
if self.formatter:
body = self.format(record)
else:
body = record.msg
if isinstance(record.msg, str) and record.args:
body = record.msg % record.args
else:
body = record.msg

# related to https://github.com/open-telemetry/opentelemetry-python/issues/3548
# Severity Text = WARN as defined in https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#displaying-severity.
Expand Down
49 changes: 49 additions & 0 deletions opentelemetry-sdk/tests/logs/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,55 @@ def test_simple_log_record_processor_different_msg_types(self):
]
self.assertEqual(expected, emitted)

def test_simple_log_record_processor_different_msg_types_with_formatter(
self,
):
exporter = InMemoryLogExporter()
log_record_processor = BatchLogRecordProcessor(exporter)

provider = LoggerProvider()
provider.add_log_record_processor(log_record_processor)

logger = logging.getLogger("different_msg_types")
handler = LoggingHandler(logger_provider=provider)
handler.setFormatter(
logging.Formatter("%(name)s - %(levelname)s - %(message)s")
)
logger.addHandler(handler)

logger.warning("warning message: %s", "possible upcoming heatwave")
logger.error("Very high rise in temperatures across the globe")
logger.critical("Temperature hits high 420 C in Hyderabad")
logger.warning(["list", "of", "strings"])
logger.error({"key": "value"})
log_record_processor.shutdown()

finished_logs = exporter.get_finished_logs()
expected = [
(
"different_msg_types - WARNING - warning message: possible upcoming heatwave",
"WARN",
),
(
"different_msg_types - ERROR - Very high rise in temperatures across the globe",
"ERROR",
),
(
"different_msg_types - CRITICAL - Temperature hits high 420 C in Hyderabad",
"CRITICAL",
),
(
"different_msg_types - WARNING - ['list', 'of', 'strings']",
"WARN",
),
("different_msg_types - ERROR - {'key': 'value'}", "ERROR"),
]
emitted = [
(item.log_record.body, item.log_record.severity_text)
for item in finished_logs
]
self.assertEqual(expected, emitted)


class TestBatchLogRecordProcessor(ConcurrencyTestBase):
def test_emit_call_log_record(self):
Expand Down
42 changes: 41 additions & 1 deletion opentelemetry-sdk/tests/logs/test_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,53 @@ def test_log_record_trace_correlation(self):
self.assertEqual(log_record.span_id, span_context.span_id)
self.assertEqual(log_record.trace_flags, span_context.trace_flags)

def test_warning_without_formatter(self):
processor, logger = set_up_test_logging(logging.WARNING)
logger.warning("Test message")

log_record = processor.get_log_record(0)
self.assertEqual(log_record.body, "Test message")

def test_exception_without_formatter(self):
processor, logger = set_up_test_logging(logging.WARNING)
logger.exception("Test exception")

log_record = processor.get_log_record(0)
self.assertEqual(log_record.body, "Test exception")

def test_warning_with_formatter(self):
processor, logger = set_up_test_logging(
logging.WARNING,
formatter=logging.Formatter(
"%(name)s - %(levelname)s - %(message)s"
),
)
logger.warning("Test message")

log_record = processor.get_log_record(0)
self.assertEqual(log_record.body, "foo - WARNING - Test message")

def test_log_body_is_always_string_with_formatter(self):
processor, logger = set_up_test_logging(
logging.WARNING,
formatter=logging.Formatter(
"%(name)s - %(levelname)s - %(message)s"
),
)
logger.warning(["something", "of", "note"])

log_record = processor.get_log_record(0)
self.assertIsInstance(log_record.body, str)


def set_up_test_logging(level):
def set_up_test_logging(level, formatter=None):
logger_provider = LoggerProvider()
processor = FakeProcessor()
logger_provider.add_log_record_processor(processor)
logger = logging.getLogger("foo")
handler = LoggingHandler(level=level, logger_provider=logger_provider)
if formatter:
handler.setFormatter(formatter)
logger.addHandler(handler)
return processor, logger

Expand Down

0 comments on commit e6486be

Please sign in to comment.