2

Python: 3.7 json_logging: 1.3.0

I have a need to implement JSON-format logger for a Python application (for integration with Logstash). Currently, I have two different handlers implemented (one logging.StreamHandler for logging to console in a more "human" readable format, one logging.handlers.RotatingFileHandler).

I would like to retain the possibility of logging with these different handlers, as having JSON formatted output on console is not very friendly. I am using json_logging library for formatting the JSON logging part.

The issue I am having is trying to setup a custom JSON formatter. The default one has a lot of redundant information which I would like to remove (example, because I have custom logging function which create a log message from few input parameters, JSON formatted parameters "module" and "line_no" will always carry the same information (of my custom log function) and not the actual line number and module).

Logging setup is read from a configuration yaml file:

---
version: 1
disable_existing_loggers: False
formatters:
    console_formatter:
        format: "%(asctime)s %(process)d %(thread)d %(levelname)s %(message)s"
        datefmt: "%Y-%m-%dT%H:%M:%S%z"
    file_formatter:
        format: "%(asctime)s %(process)d %(thread)d %(levelname)s %(message)s"
        datefmt: "%Y-%m-%dT%H:%M:%S"
        class: json_logging.JSONLogFormatter
         
handlers:
    console:
        class: logging.StreamHandler
        level: DEBUG
        formatter: console_formatter
        stream: ext://sys.stdout
    
    # Default log file gets written into a file inside the project folder
    debug_file_handler:
        class: logging.handlers.RotatingFileHandler
        level: DEBUG
        formatter: file_formatter
        filename:  /var/log/runtime.log
        maxBytes: 10485760 # 10MB
        backupCount: 30
        encoding: utf8

loggers:
    my_module:
        level: DEBUG
        handlers: [console]
        propagate: no

root:
    level: DEBUG
    handlers: [console, debug_file_handler]

Snippet of the setup_logging function which reads the parameter file and sets up the logging:

        if path is None:
            logging.warning("Log configuration file NOT found: " + ','.join(value, default_path, package_path))
            logging.basicConfig(level=default_level, format=format)
        else:
            logging.debug("Log configuration file found: " + path)
            with open(path, 'rt') as f:
                config = yaml.safe_load(f.read())
            logging.config.dictConfig(config)

Using the class: json_logging.JSONLogFormatter in one of the handlers I am able to log in JSON format in only file_formatter and retain the non-JSON structure in console.

The issue comes into picture when I try to setup a custom JSON formatter. I am using the example provided in library's github: https://github.com/bobbui/json-logging-python/blob/master/example/custom_log_format.py

There, the custom class is provided for the init call to setup function json_logging.init_non_web(custom_formatter=CustomJSONLog, enable_json=True)

The problem is, that this function configures all handlers to use the same format. Which also changes the console formatter output to JSON.

I have tried to use getLogger and then setting the formatter to only the fileHandler, however that still changes all formatters:

            log = logging.getLogger()
            for hdlr in log.handlers[:]:  # remove the existing file handlers
                if isinstance(hdlr, logging.FileHandler):
                    hdlr.setFormatter(json_logging.init_non_web(custom_formatter=CustomJSONLog, enable_json=True))

Could someone help me in finding the way to use a custom JSON formatter for only a single handler?

1
  • If you don't want to reinvent the wheel, using structlog might be a good solution as it has good support for Logstash Commented Jun 12, 2021 at 22:39

1 Answer 1

3

It seems like the problem you're having is due to json_logging not "playing nicely" with all the different ways that the stdlib logging can be configured.

This answer describes how to configure json-formatted logs using only the standard library.

After you do that, you can simply configure handler-specific formatters as you've already attempted to do in your question.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, that's a useful link. Would give a +1 on the answer, unfortunately don't have enough rep for that :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.