Skip to content

Commit 302bfb3

Browse files
majortisnik
authored andcommitted
RSPEED-2471: Use plain log handler in non-TTY environments
RichHandler's columnar layout falls back to 80 columns without a TTY, leaving only ~40 chars for log messages. Tracebacks become unreadable. Fall back to a plain StreamHandler when stderr is not a terminal. Signed-off-by: Major Hayden <major@redhat.com>
1 parent ff9276d commit 302bfb3

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

src/lightspeed_stack.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from utils import schema_dumper
2020
from constants import LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, DEFAULT_LOG_LEVEL
2121

22-
FORMAT = "%(message)s"
2322
# Read log level from environment variable with validation
2423
log_level_str = os.environ.get(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, DEFAULT_LOG_LEVEL)
2524
log_level = getattr(logging, log_level_str.upper(), None)
@@ -29,9 +28,24 @@
2928
file=sys.stderr,
3029
)
3130
log_level = getattr(logging, DEFAULT_LOG_LEVEL)
32-
logging.basicConfig(
33-
level=log_level, format=FORMAT, datefmt="[%X]", handlers=[RichHandler()], force=True
34-
)
31+
32+
# RichHandler's columnar layout produces very narrow log output in containers
33+
# without a TTY (Rich falls back to 80 columns, columns consume ~40 of those).
34+
# Use a plain format when there's no terminal attached.
35+
if sys.stderr.isatty():
36+
logging.basicConfig(
37+
level=log_level,
38+
format="%(message)s",
39+
datefmt="[%X]",
40+
handlers=[RichHandler()],
41+
force=True,
42+
)
43+
else:
44+
logging.basicConfig(
45+
level=log_level,
46+
format="%(asctime)s %(levelname)-8s %(name)s:%(lineno)d %(message)s",
47+
force=True,
48+
)
3549

3650
logger = get_logger(__name__)
3751

src/log.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import logging
44
import os
5+
import sys
6+
57
from rich.logging import RichHandler
68

79
from constants import LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, DEFAULT_LOG_LEVEL
@@ -24,12 +26,24 @@ def get_logger(name: str) -> logging.Logger:
2426
"""
2527
logger = logging.getLogger(name)
2628

27-
# Skip reconfiguration if logger already has a RichHandler from a prior call
28-
if any(isinstance(h, RichHandler) for h in logger.handlers):
29+
# Skip reconfiguration if logger already has handlers from a prior call
30+
if logger.handlers:
2931
return logger
3032

31-
# Attach RichHandler before any log calls so warnings use consistent formatting
32-
logger.handlers = [RichHandler()]
33+
# RichHandler's columnar layout (timestamp, level, right-aligned filename) assumes
34+
# a real terminal. In containers without a TTY, Rich falls back to 80 columns and
35+
# the columns consume most of that width, leaving ~40 chars for the actual message.
36+
# Tracebacks become nearly unreadable. Use a plain StreamHandler when there's no TTY.
37+
if sys.stderr.isatty():
38+
logger.handlers = [RichHandler()]
39+
else:
40+
handler = logging.StreamHandler()
41+
handler.setFormatter(
42+
logging.Formatter(
43+
"%(asctime)s %(levelname)-8s %(name)s:%(lineno)d %(message)s"
44+
)
45+
)
46+
logger.handlers = [handler]
3347
logger.propagate = False
3448

3549
# Read log level from environment variable with default fallback

0 commit comments

Comments
 (0)