"""Tests for structured JSON logging.""" import json import logging from derp.log import JsonFormatter class TestJsonFormatter: """Test JsonFormatter output.""" @staticmethod def _make_record(msg: str, level: int = logging.INFO, name: str = "derp.test") -> logging.LogRecord: """Create a LogRecord for testing.""" return logging.LogRecord( name=name, level=level, pathname="", lineno=0, msg=msg, args=(), exc_info=None, ) def test_basic_fields(self): fmt = JsonFormatter() record = self._make_record("hello world") output = fmt.format(record) entry = json.loads(output) assert entry["msg"] == "hello world" assert entry["level"] == "info" assert entry["logger"] == "derp.test" assert "ts" in entry def test_level_name(self): fmt = JsonFormatter() record = self._make_record("warn", level=logging.WARNING) entry = json.loads(fmt.format(record)) assert entry["level"] == "warning" def test_no_exc_key_without_exception(self): fmt = JsonFormatter() record = self._make_record("clean") entry = json.loads(fmt.format(record)) assert "exc" not in entry def test_exception_included(self): fmt = JsonFormatter() import sys try: raise ValueError("boom") except ValueError: exc_info = sys.exc_info() record = logging.LogRecord( name="derp.test", level=logging.ERROR, pathname="", lineno=0, msg="failed", args=(), exc_info=exc_info, ) entry = json.loads(fmt.format(record)) assert "exc" in entry assert "ValueError" in entry["exc"] assert "boom" in entry["exc"] def test_output_is_single_line(self): fmt = JsonFormatter() record = self._make_record("one liner") output = fmt.format(record) assert "\n" not in output def test_unicode_preserved(self): fmt = JsonFormatter() record = self._make_record("cafe\u0301") entry = json.loads(fmt.format(record)) assert entry["msg"] == "cafe\u0301" def test_timestamp_format(self): fmt = JsonFormatter() record = self._make_record("ts check") entry = json.loads(fmt.format(record)) # ISO-ish: YYYY-MM-DDTHH:MM:SS assert "T" in entry["ts"] assert len(entry["ts"]) == 19