Skip to content

Commit 13c1022

Browse files
committed
feat: split console and file logging levels
Add console_level (default WARNING) and file_level (default = level) to LoggingConfig so INFO messages stay in the rule log file while the console stays readable under parallel execution.
1 parent f6d5fee commit 13c1022

5 files changed

Lines changed: 84 additions & 13 deletions

File tree

config/config.default.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ tutorial: false
1111
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#logging
1212
logging:
1313
level: INFO
14+
console_level: WARNING
15+
file_level:
1416
format: "%(levelname)s:%(name)s:%(message)s"
1517

1618
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#remote

config/schema.default.json

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2848,7 +2848,7 @@
28482848
"properties": {
28492849
"level": {
28502850
"default": "INFO",
2851-
"description": "Restrict console outputs to all infos, warning or errors only",
2851+
"description": "Root log level. Messages below this level are discarded before reaching any handler.",
28522852
"enum": [
28532853
"DEBUG",
28542854
"INFO",
@@ -2858,6 +2858,37 @@
28582858
],
28592859
"type": "string"
28602860
},
2861+
"console_level": {
2862+
"default": "WARNING",
2863+
"description": "Minimum level emitted to the console (stderr). Defaults to ``WARNING`` so parallel rule output stays readable; the full log is kept in the rule's log file.",
2864+
"enum": [
2865+
"DEBUG",
2866+
"INFO",
2867+
"WARNING",
2868+
"ERROR",
2869+
"CRITICAL"
2870+
],
2871+
"type": "string"
2872+
},
2873+
"file_level": {
2874+
"anyOf": [
2875+
{
2876+
"enum": [
2877+
"DEBUG",
2878+
"INFO",
2879+
"WARNING",
2880+
"ERROR",
2881+
"CRITICAL"
2882+
],
2883+
"type": "string"
2884+
},
2885+
{
2886+
"type": "null"
2887+
}
2888+
],
2889+
"default": null,
2890+
"description": "Minimum level written to the rule log file. Defaults to ``level`` when unset."
2891+
},
28612892
"format": {
28622893
"default": "%(levelname)s:%(name)s:%(message)s",
28632894
"description": "Custom format for log messages. See `LogRecord <https://docs.python.org/3/library/logging.html#logging.LogRecord>`_ attributes.",
@@ -8182,7 +8213,7 @@
81828213
"properties": {
81838214
"level": {
81848215
"default": "INFO",
8185-
"description": "Restrict console outputs to all infos, warning or errors only",
8216+
"description": "Root log level. Messages below this level are discarded before reaching any handler.",
81868217
"enum": [
81878218
"DEBUG",
81888219
"INFO",
@@ -8192,6 +8223,37 @@
81928223
],
81938224
"type": "string"
81948225
},
8226+
"console_level": {
8227+
"default": "WARNING",
8228+
"description": "Minimum level emitted to the console (stderr). Defaults to ``WARNING`` so parallel rule output stays readable; the full log is kept in the rule's log file.",
8229+
"enum": [
8230+
"DEBUG",
8231+
"INFO",
8232+
"WARNING",
8233+
"ERROR",
8234+
"CRITICAL"
8235+
],
8236+
"type": "string"
8237+
},
8238+
"file_level": {
8239+
"anyOf": [
8240+
{
8241+
"enum": [
8242+
"DEBUG",
8243+
"INFO",
8244+
"WARNING",
8245+
"ERROR",
8246+
"CRITICAL"
8247+
],
8248+
"type": "string"
8249+
},
8250+
{
8251+
"type": "null"
8252+
}
8253+
],
8254+
"default": null,
8255+
"description": "Minimum level written to the rule log file. Defaults to ``level`` when unset."
8256+
},
81958257
"format": {
81968258
"default": "%(levelname)s:%(name)s:%(message)s",
81978259
"description": "Custom format for log messages. See `LogRecord <https://docs.python.org/3/library/logging.html#logging.LogRecord>`_ attributes.",

doc/release_notes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Release Notes
2020

2121
* perf: Optimize dask settings for computing weather-dependent profiles (https://github.com/PyPSA/pypsa-eur/pull/2137).
2222

23+
* Split logging levels between console and log file: the console now defaults to ``WARNING`` while the rule log file still captures ``INFO``. Configure via ``logging.console_level`` and ``logging.file_level`` (https://github.com/PyPSA/pypsa-eur/pull/2144).
24+
2325
PyPSA-Eur v2026.02.0 (18th February 2026)
2426
=========================================
2527

scripts/_helpers.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ def configure_logging(snakemake, skip_handlers=False):
262262

263263
kwargs = snakemake.config.get("logging", dict()).copy()
264264
kwargs.setdefault("level", "INFO")
265+
console_level = kwargs.pop("console_level", "WARNING")
266+
file_level = kwargs.pop("file_level", None) or kwargs["level"]
265267

266268
if skip_handlers is False:
267269
fallback_path = Path(__file__).parent.joinpath(
@@ -270,16 +272,11 @@ def configure_logging(snakemake, skip_handlers=False):
270272
logfile = snakemake.log.get(
271273
"python", snakemake.log[0] if snakemake.log else fallback_path
272274
)
273-
kwargs.update(
274-
{
275-
"handlers": [
276-
# Prefer the 'python' log, otherwise take the first log for each
277-
# Snakemake rule
278-
logging.FileHandler(logfile),
279-
logging.StreamHandler(),
280-
]
281-
}
282-
)
275+
file_handler = logging.FileHandler(logfile)
276+
file_handler.setLevel(file_level)
277+
stream_handler = logging.StreamHandler()
278+
stream_handler.setLevel(console_level)
279+
kwargs["handlers"] = [file_handler, stream_handler]
283280
logging.basicConfig(**kwargs)
284281

285282
# Setup a function to handle uncaught exceptions and include them with their stacktrace into logfiles

scripts/lib/validation/config/_schema.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,15 @@ class LoggingConfig(ConfigModel):
4646

4747
level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
4848
"INFO",
49-
description="Restrict console outputs to all infos, warning or errors only",
49+
description="Root log level. Messages below this level are discarded before reaching any handler.",
50+
)
51+
console_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
52+
"WARNING",
53+
description="Minimum level emitted to the console (stderr). Defaults to ``WARNING`` so parallel rule output stays readable; the full log is kept in the rule's log file.",
54+
)
55+
file_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None = Field(
56+
None,
57+
description="Minimum level written to the rule log file. Defaults to ``level`` when unset.",
5058
)
5159
format: str = Field(
5260
"%(levelname)s:%(name)s:%(message)s",

0 commit comments

Comments
 (0)