Add custom handler to log root level with logging.basicConfig()

Question:

I am trying to build a custom log handler which sends log messages over http. However, I do not want to add the handler with addHandler() method. I want the custom handler to be configured directly at log root level with logging.basicConfig() in particular to ensure all log messages triggered from different modules with different loggers are sent over http. How can I achieve this?

Here is my current code

"""Entrypoint to execute python scripts."""
import argparse
import logging
import sys
import utils
from batch import Batch
from data_source import DataSource


# Load default logging configuration
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)


# Define custom log handler
class CustomLogHandler(logging.Handler):
    """Custom logs handler to send log messages to GraphQL API."""

    def __init__(self, authorization: str, batch_id: int):
        logging.Handler.__init__(self)
        self.authorization = authorization
        self.batch_id = str(batch_id)

    def emit(self, log_record):
        file_name = log_record.name
        log_level = log_record.levelname
        log_message = self.format(log_record)

        # Do stuff here...
        utils.execute_graphql_request(self.authorization, mutation)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Entry point to execute data quality scripts.')
    parser.add_argument('authorization', type=str, help='Authentication token of the user')
    parser.add_argument('method', type=str, help='Method to be executed: execute_batch, test_data_source')
    parser.add_argument('id', type=int, help='Id of the object on which to execute the method.')
    arguments = parser.parse_args()

    authorization = arguments.authorization
    method = arguments.method

    if method == 'execute_batch':
        batch_id = arguments.id

        # Overwrite log root basic config to send logs to GraphQL API when executing a batch
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[logging.StreamHandler(), CustomLogHandler(authorization, batch_id)])

        batch = Batch()
        batch.execute(authorization, batch_id)

    elif [...]
Asked By: Alexis.Rolland

||

Answers:

you have two ways of adding a handler to the root logger,
either add it to the basicConfig:

    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(message)s",
        handlers=[
            logging.StreamHandler(),
            CustomLogHandler()
        ]
    )

or after your basic config is done you can add it to the root logger (to ensure propagation) like this:

root_log = logging.getLogger()
root_log.addHandler(CustomLogHandler())

then whenever you do a

import logging

log = logging.getLogger(__name__)
log.info("message")

The “message” log should be sent through your root logger.

Answered By: Laurent Erignoux
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.