Andy
Andy

Reputation: 3522

Is it possible to inject a log level into structured data in python logging

I'm trying to write some structure logs out on stdout from my python program. Specifically I'm trying to write json that is compliant with the following, so that when it's run in GCP, it gets picked up by stack driver and interpreted as structured data:

https://cloud.google.com/run/docs/logging#run_manual_logging-python

Looking at the python docs, I could create a class for my structured data, and have it render down to a single line json string:

https://docs.python.org/2/howto/logging-cookbook.html#implementing-structured-logging

What I'm stuck on however is; how do I add the log level to that structured data without having redundant looking log calls:

class StructuredMessage(object):
def __init__(self, **kwargs):
    self.kwargs = kwargs

def __str__(self):
    return json.dumps(self.kwargs)

// Ideally I should have to type level='INFO' here, is there a way to get the logging
// module to do something to insert that information on the StructuredMessage instance?
logging.info(StructuredMessage(level='INFO'))

Upvotes: 1

Views: 346

Answers (1)

Vinay Sajip
Vinay Sajip

Reputation: 99510

There are numerous ways you can do this - one would be using a simple helper function like this (it assumes import logging has been done):

def log_structured(logger, level, **kwargs):
    kwargs[level] = level
    # you could also inject the logger name into kwargs here ...
    # convert e.g. string 'INFO' to logging.INFO
    # assumes you only use the standard levels defined in logging
    level = getattr(logging, level)
    logger.log(level, StructuredMessage(**kwargs))

Functions like logging.info() use the root logger, so you could do something like

root_logger = logging.getLogger()
log_structured(root_logger, 'INFO', foo='bar', bar='baz', num=123, fnum=123.456)

Upvotes: 1

Related Questions