Skip to content

Commit 325d29a

Browse files
authored
Merge pull request #1253 from lightspeed-core/TamiTakamiya/envvar-to-force-stream-handler
Environment variable to force StreamHandler instead of RichHandler
2 parents 12d3304 + 0c3a1d2 commit 325d29a

3 files changed

Lines changed: 58 additions & 11 deletions

File tree

src/constants.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@
5252
- Do **NOT** use all uppercase - capitalize only the first letter of significant words
5353
- Exclude articles and prepositions (e.g., "a," "the," "of," "on," "in")
5454
- Exclude all punctuation and interpunction marks (e.g., . , : ; ! ? | "")
55-
- Retain original abbreviations. Do not expand an abbreviation if its specific meaning in the context is unknown or ambiguous.
55+
- Retain original abbreviations. Do not expand an abbreviation if its specific meaning in the
56+
context is unknown or ambiguous.
5657
- Neutral objective language
5758
- Do **NOT** provide explanations, reasoning, or "processing steps".
5859
- Do **NOT** provide multiple options (e.g., do not use "or").
@@ -188,3 +189,6 @@
188189
DEFAULT_LOG_LEVEL = "INFO"
189190
# Default log format for plain-text logging in non-TTY environments
190191
DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)-8s %(name)s:%(lineno)d %(message)s"
192+
# Environment variable to force StreamHandler instead of RichHandler
193+
# Set to any non-empty value to disable RichHandler
194+
LIGHTSPEED_STACK_DISABLE_RICH_HANDLER_ENV_VAR = "LIGHTSPEED_STACK_DISABLE_RICH_HANDLER"

src/log.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
from rich.logging import RichHandler
88

99
from constants import (
10-
LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR,
11-
DEFAULT_LOG_LEVEL,
1210
DEFAULT_LOG_FORMAT,
11+
DEFAULT_LOG_LEVEL,
12+
LIGHTSPEED_STACK_DISABLE_RICH_HANDLER_ENV_VAR,
13+
LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR,
1314
)
1415

1516

@@ -49,18 +50,23 @@ def resolve_log_level() -> int:
4950

5051
def create_log_handler() -> logging.Handler:
5152
"""
52-
Create and return a configured log handler based on TTY availability.
53+
Create and return a configured log handler based on TTY availability and environment settings.
5354
54-
If stderr is connected to a terminal (TTY), returns a RichHandler for
55-
rich-formatted console output. Otherwise, returns a StreamHandler with
55+
If LIGHTSPEED_STACK_DISABLE_RICH_HANDLER is set to any non-empty value,
56+
returns a StreamHandler with plain-text formatting. Otherwise, if stderr
57+
is connected to a terminal (TTY), returns a RichHandler for rich-formatted
58+
console output. If neither condition is met, returns a StreamHandler with
5659
plain-text formatting suitable for non-TTY environments (e.g., containers).
5760
58-
Parameters:
59-
None
60-
6161
Returns:
6262
logging.Handler: A configured handler instance (RichHandler or StreamHandler).
6363
"""
64+
# Check if RichHandler is explicitly disabled via environment variable
65+
if os.environ.get(LIGHTSPEED_STACK_DISABLE_RICH_HANDLER_ENV_VAR):
66+
handler = logging.StreamHandler()
67+
handler.setFormatter(logging.Formatter(DEFAULT_LOG_FORMAT))
68+
return handler
69+
6470
if sys.stderr.isatty():
6571
# RichHandler's columnar layout assumes a real terminal.
6672
# RichHandler handles its own formatting, so no formatter is set.

tests/unit/test_log.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
from pytest_mock import MockerFixture
77
from rich.logging import RichHandler
88

9-
from log import get_logger, resolve_log_level, create_log_handler
10-
from constants import LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, DEFAULT_LOG_FORMAT
9+
from constants import (
10+
DEFAULT_LOG_FORMAT,
11+
LIGHTSPEED_STACK_DISABLE_RICH_HANDLER_ENV_VAR,
12+
LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR,
13+
)
14+
from log import create_log_handler, get_logger, resolve_log_level
1115

1216

1317
def test_get_logger() -> None:
@@ -116,3 +120,36 @@ def test_create_log_handler_non_tty_format(mocker: MockerFixture) -> None:
116120
assert handler.formatter is not None
117121
# pylint: disable=protected-access
118122
assert handler.formatter._fmt == DEFAULT_LOG_FORMAT
123+
124+
125+
def test_create_log_handler_disable_rich_with_tty(
126+
mocker: MockerFixture, monkeypatch: pytest.MonkeyPatch
127+
) -> None:
128+
"""Test that RichHandler is disabled when env var is set, even with TTY."""
129+
mocker.patch("sys.stderr.isatty", return_value=True)
130+
monkeypatch.setenv(LIGHTSPEED_STACK_DISABLE_RICH_HANDLER_ENV_VAR, "1")
131+
handler = create_log_handler()
132+
assert isinstance(handler, logging.StreamHandler)
133+
assert not isinstance(handler, RichHandler)
134+
135+
136+
def test_create_log_handler_disable_rich_format(
137+
mocker: MockerFixture, monkeypatch: pytest.MonkeyPatch
138+
) -> None:
139+
"""Test that disabled RichHandler uses DEFAULT_LOG_FORMAT."""
140+
mocker.patch("sys.stderr.isatty", return_value=True)
141+
monkeypatch.setenv(LIGHTSPEED_STACK_DISABLE_RICH_HANDLER_ENV_VAR, "true")
142+
handler = create_log_handler()
143+
assert handler.formatter is not None
144+
# pylint: disable=protected-access
145+
assert handler.formatter._fmt == DEFAULT_LOG_FORMAT
146+
147+
148+
def test_create_log_handler_enable_rich_when_env_var_empty(
149+
mocker: MockerFixture, monkeypatch: pytest.MonkeyPatch
150+
) -> None:
151+
"""Test that RichHandler is used when env var is empty string."""
152+
mocker.patch("sys.stderr.isatty", return_value=True)
153+
monkeypatch.setenv(LIGHTSPEED_STACK_DISABLE_RICH_HANDLER_ENV_VAR, "")
154+
handler = create_log_handler()
155+
assert isinstance(handler, RichHandler)

0 commit comments

Comments
 (0)