From f4d3c65b2b389f0c7a473021476deac85320abd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Zacchino?= Date: Wed, 24 Sep 2025 15:24:46 +0000 Subject: [PATCH 1/2] logging_json: enhance logging output by splitting levels into stdout and stderr --- logging_json/README.rst | 4 ++++ logging_json/json_log.py | 38 ++++++++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/logging_json/README.rst b/logging_json/README.rst index 4d60884d..d6929e7e 100644 --- a/logging_json/README.rst +++ b/logging_json/README.rst @@ -12,3 +12,7 @@ The json logging is activated with the environment variable In order to have the logs from the start of the server, you should add ``logging_json`` in the ``--load`` flag or in the ``server_wide_modules`` option in the configuration file. + +You can split the logs in stderr and stdout with the environment variable +``ODOO_LOGGING_JSON_STDERR`` set to ``1``. In this case, the logs with a level +of WARNING or above will be sent to stderr, the others to stdout. diff --git a/logging_json/json_log.py b/logging_json/json_log.py index 9c00922e..f9e60fab 100644 --- a/logging_json/json_log.py +++ b/logging_json/json_log.py @@ -3,6 +3,7 @@ import logging import os +import sys import threading import uuid @@ -34,11 +35,40 @@ def add_fields(self, log_record, record, message_dict): if is_true(os.environ.get("ODOO_LOGGING_JSON")): - formatted_message = ( - "%(asctime)s %(pid)s %(levelname)s %(dbname)s %(name)s: %(message)s" - ) + formatted_message = "%(asctime)s %(pid)s %(levelname)s %(dbname)s %(name)s: %(message)s" formatter = OdooJsonFormatter(formatted_message) - logging.getLogger().handlers[0].formatter = formatter + + if is_true(os.environ.get("ODOO_LOGGING_JSON_STDERR")): + + class MaxLevelFilter(logging.Filter): + def __init__(self, max_level): + self.max_level = max_level + + def filter(self, record): + return record.levelno < self.max_level + + # keep the original level + root_logger = logging.getLogger() + original_level = root_logger.level + + # Split lower levels into stdout + stdout_handler = logging.StreamHandler(sys.stdout) + stdout_handler.setLevel(logging.NOTSET) + stdout_handler.addFilter(MaxLevelFilter(logging.WARNING)) + stdout_handler.setFormatter(formatter) + + # Split WARNING and upper into stderr + stderr_handler = logging.StreamHandler(sys.stderr) + stderr_handler.setLevel(logging.WARNING) + stderr_handler.setFormatter(formatter) + + # Replace handlers + root_logger.handlers = [] + root_logger.setLevel(original_level) + root_logger.addHandler(stdout_handler) + root_logger.addHandler(stderr_handler) + else: + logging.getLogger().handlers[0].formatter = formatter # monkey patch Request constructor to store request_uuid From 92b965e338a1a9a8b098f9074a3077fc3e08193c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Todorovich?= Date: Mon, 1 Dec 2025 08:39:57 -0300 Subject: [PATCH 2/2] [FIX] pre-commit: after merge --- logging_json/json_log.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/logging_json/json_log.py b/logging_json/json_log.py index f9e60fab..2a2fedfd 100644 --- a/logging_json/json_log.py +++ b/logging_json/json_log.py @@ -35,7 +35,9 @@ def add_fields(self, log_record, record, message_dict): if is_true(os.environ.get("ODOO_LOGGING_JSON")): - formatted_message = "%(asctime)s %(pid)s %(levelname)s %(dbname)s %(name)s: %(message)s" + formatted_message = ( + "%(asctime)s %(pid)s %(levelname)s %(dbname)s %(name)s: %(message)s" + ) formatter = OdooJsonFormatter(formatted_message) if is_true(os.environ.get("ODOO_LOGGING_JSON_STDERR")):