Skip to content

Commit 0f69c11

Browse files
author
Mateusz
committed
Simplify default log format: drop stream_id and env tags, shorten PID
Remove [stream_id=...] and [prod]/[test] from the default formatter strings. Show only the last four decimal digits of the process id as [pid=*XXXX]. Align Uvicorn formatters and add unit tests for format_log_pid_short and EnvironmentTaggingFormatter. EnvironmentTaggingFilter still sets env_tag for custom formats that reference it. Made-with: Cursor
1 parent 7a18e43 commit 0f69c11

3 files changed

Lines changed: 62 additions & 31 deletions

File tree

src/core/common/logging_utils.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
- Redaction of sensitive information
77
- Consistent log level usage
88
- Enhanced context information
9-
- Test/production environment tagging
9+
- Optional test/production ``env_tag`` on records (for filters and custom formats)
1010
"""
1111

1212
from __future__ import annotations
@@ -86,6 +86,21 @@ def get_environment_tag() -> str:
8686
return _get_environment_tag()
8787

8888

89+
def format_log_pid_short(process: int | None) -> str:
90+
"""Format a process id for log lines: asterisk plus last four decimal digits.
91+
92+
Used inside ``[pid=...]``, e.g. process ``440852`` -> ``*0852`` so the tag reads
93+
``[pid=*0852]``.
94+
"""
95+
if process is None:
96+
return "*----"
97+
try:
98+
pid_int = int(process)
99+
except (TypeError, ValueError):
100+
return "*----"
101+
return f"*{pid_int % 10000:04d}"
102+
103+
89104
class EnvironmentTaggingFilter(logging.Filter):
90105
"""Logging filter that adds environment tags to log records."""
91106

@@ -107,9 +122,10 @@ def filter(self, record: logging.LogRecord) -> bool: # type: ignore[override]
107122

108123

109124
class EnvironmentTaggingFormatter(logging.Formatter):
110-
"""Logging formatter that includes environment tags and PID.
125+
"""Logging formatter with shortened ``pid`` placeholder for log lines.
111126
112-
Format: YYYY-MM-DD HH:MM:SS,mmm [LEVEL] [env] [pid=XXX] name:lineno message
127+
Default format: ``YYYY-MM-DD HH:MM:SS,mmm [LEVEL] [pid=*XXXX] name:lineno message``
128+
where ``*XXXX`` is an asterisk plus the process id modulo 10000 (four digits).
113129
"""
114130

115131
def __init__(
@@ -118,15 +134,13 @@ def __init__(
118134
datefmt: str | None = None,
119135
style: Literal["%", "{", "$"] = "%",
120136
) -> None:
121-
# Set default format if none provided - compact level, env tag, and PID
122137
if fmt is None:
123-
fmt = "%(asctime)s [%(levelname)s] [%(env_tag)s] [pid=%(process)d] [stream_id=%(stream_id)s] %(name)s:%(lineno)d %(message)s"
138+
fmt = "%(asctime)s [%(levelname)s] [pid=%(pid_short)s] %(name)s:%(lineno)d %(message)s"
124139
super().__init__(fmt, datefmt, style=style)
125140

126141
def format(self, record: logging.LogRecord) -> str:
127-
"""Populate optional logging fields used by the global format."""
128-
if not hasattr(record, "stream_id"):
129-
record.stream_id = "-"
142+
"""Set ``pid_short`` on the record for the format string."""
143+
record.pid_short = format_log_pid_short(getattr(record, "process", None))
130144
return super().format(record)
131145

132146

@@ -533,9 +547,8 @@ def install_environment_tagging() -> None:
533547
for handler in list(root.handlers):
534548
try:
535549
handler.addFilter(filter_instance)
536-
# Update formatter to include environment tag
550+
# Normalize formatter to EnvironmentTaggingFormatter (pid_short, etc.)
537551
if isinstance(handler.formatter, logging.Formatter):
538-
# Use the environment tagging formatter
539552
new_formatter = EnvironmentTaggingFormatter(
540553
fmt=handler.formatter._fmt, datefmt=handler.formatter.datefmt
541554
)
@@ -560,19 +573,17 @@ def configure_logging_with_environment_tagging(
560573
use_colors: bool = False,
561574
console_stream: str = "stderr",
562575
) -> None:
563-
"""Configure logging with environment tagging.
576+
"""Configure root logging, structlog, env-tag filter, and standard formatters.
564577
565578
Args:
566579
level: Logging level
567580
log_format: Optional log format string
568581
log_file: Optional log file path
569582
use_colors: Whether to enable colored output
570583
"""
571-
# Use default format with environment tag if none provided - compact level, env tag, and PID
572584
if log_format is None:
573-
log_format = "%(asctime)s [%(levelname)s] [%(env_tag)s] [pid=%(process)d] [stream_id=%(stream_id)s] %(name)s:%(lineno)d %(message)s"
585+
log_format = "%(asctime)s [%(levelname)s] [pid=%(pid_short)s] %(name)s:%(lineno)d %(message)s"
574586

575-
# Create formatter with environment tag support
576587
formatter = EnvironmentTaggingFormatter(fmt=log_format)
577588

578589
# Create handlers
@@ -588,9 +599,8 @@ def configure_logging_with_environment_tagging(
588599
from rich.logging import RichHandler
589600

590601
# Use RichHandler for colored output
591-
# Define a simplified format for Rich that excludes time/level (Rich handles them)
592-
# but includes the environment tag and location info
593-
rich_fmt = "[%(env_tag)s] %(name)s:%(lineno)d %(message)s"
602+
# Simplified format for Rich (time/level come from Rich); keep pid + location
603+
rich_fmt = "[pid=%(pid_short)s] %(name)s:%(lineno)d %(message)s"
594604
rich_formatter = EnvironmentTaggingFormatter(fmt=rich_fmt)
595605

596606
console_handler = RichHandler(

src/core/common/uvicorn_logging.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import logging
44
from typing import Any
55

6-
from src.core.common.logging_utils import get_environment_tag
6+
from src.core.common.logging_utils import format_log_pid_short
77

88

99
class UvicornEnvironmentTaggingFormatter(logging.Formatter):
10-
"""Custom formatter for Uvicorn that adds environment tags like the main app.
10+
"""Custom formatter for Uvicorn aligned with the main app log layout.
1111
12-
This ensures Uvicorn log messages match the format of the rest of the application:
13-
YYYY-MM-DD HH:MM:SS,mmm [LEVEL] [env] [pid=XXX] name:lineno message
12+
Format matches :class:`EnvironmentTaggingFormatter` defaults:
13+
``YYYY-MM-DD HH:MM:SS,mmm [LEVEL] [pid=*XXXX] name:lineno message``.
1414
"""
1515

1616
def __init__(
@@ -19,16 +19,14 @@ def __init__(
1919
datefmt: str | None = None,
2020
use_colors: bool = False,
2121
) -> None:
22-
# Use project-standard format if none provided - compact level, env tag, and PID
2322
if fmt is None:
24-
fmt = "%(asctime)s [%(levelname)s] [%(env_tag)s] [pid=%(process)d] %(name)s:%(lineno)d %(message)s"
23+
fmt = "%(asctime)s [%(levelname)s] [pid=%(pid_short)s] %(name)s:%(lineno)d %(message)s"
2524
super().__init__(fmt, datefmt)
26-
self._env_tag = get_environment_tag()
2725
self._use_colors = use_colors
2826

2927
def format(self, record: logging.LogRecord) -> str:
30-
"""Add environment tag to the log record before formatting."""
31-
record.env_tag = self._env_tag
28+
"""Set ``pid_short`` and optional Uvicorn access fields before formatting."""
29+
record.pid_short = format_log_pid_short(getattr(record, "process", None))
3230
if not hasattr(record, "client_addr"):
3331
self._maybe_populate_access_fields(record)
3432
return super().format(record)
@@ -67,12 +65,9 @@ def get_uvicorn_logging_config(
6765
Returns:
6866
Uvicorn logging configuration dictionary.
6967
"""
70-
# Use project-standard log format matching EnvironmentTaggingFormatter in logging_utils.py
71-
# Compact level (no padding), env tag, and PID
72-
standard_fmt = "%(asctime)s [%(levelname)s] [%(env_tag)s] [pid=%(process)d] %(name)s:%(lineno)d %(message)s"
73-
# For access logs, include client address and request info
68+
standard_fmt = "%(asctime)s [%(levelname)s] [pid=%(pid_short)s] %(name)s:%(lineno)d %(message)s"
7469
access_fmt = (
75-
"%(asctime)s [%(levelname)s] [%(env_tag)s] [pid=%(process)d] %(name)s:%(lineno)d "
70+
"%(asctime)s [%(levelname)s] [pid=%(pid_short)s] %(name)s:%(lineno)d "
7671
'%(client_addr)s - "%(request_line)s" %(status_code)s'
7772
)
7873

tests/unit/core/test_core_logging_utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
from src.core.common.logging_utils import (
1212
CompatibleBoundLogger,
1313
EnvironmentTaggingFilter,
14+
EnvironmentTaggingFormatter,
1415
LogContext,
16+
format_log_pid_short,
1517
get_logger,
1618
log_async_call,
1719
log_call,
@@ -244,6 +246,30 @@ def test_environment_tagging_marks_pytest(
244246
assert hasattr(record, "env_tag")
245247
assert record.env_tag == "test"
246248

249+
def test_format_log_pid_short(self) -> None:
250+
assert format_log_pid_short(440852) == "*0852"
251+
assert format_log_pid_short(852) == "*0852"
252+
assert format_log_pid_short(5) == "*0005"
253+
assert format_log_pid_short(None) == "*----"
254+
255+
def test_environment_tagging_formatter_default_line(self) -> None:
256+
record = logging.LogRecord(
257+
name="nm",
258+
level=logging.INFO,
259+
pathname=__file__,
260+
lineno=7,
261+
msg="hi",
262+
args=(),
263+
exc_info=None,
264+
)
265+
record.process = 440852
266+
line = EnvironmentTaggingFormatter().format(record)
267+
assert "[pid=*0852]" in line
268+
assert "[INFO]" in line
269+
assert "[prod]" not in line
270+
assert "[test]" not in line
271+
assert "nm:7 hi" in line
272+
247273
def test_log_context(self) -> None:
248274
"""Test LogContext class."""
249275
mock_logger = MagicMock()

0 commit comments

Comments
 (0)