deathangel908
deathangel908

Reputation: 9699

Is it possible to inject a variable into python logger Filter

I want to add session_id to every log message. So I can do it in every request this way.

log.info('[%s] my message', self.session_id);

or even a handler. But it requires to pass %s and session variable to log method every time when I log something. Well, to skip the dirty job I can create a filter:

class ContextFilter(logging.Filter):
  def filter(self, record):
    record.my_session = 'LOL'
    return True

I'm using django + tornado so I modify LOGGING variable in settings.py:

'filters': {
  'user_filter': {
    '()': 'my_package.ContextFilter',
   }
},

'formatters': {
'verbose': {
        'format':  '[%(asctime)s %(my_session)s] %(message)s',
    },
},

And when if I write something like that:

class A(object):

  def __init__(self):
    self.session_id = random(1024)

  def process(self):
    log.info('hello')

I would get:

[11:23 LOL] hello.

Fine, now I want to inject A.session_id to filter instead of LOL. Note that session_id is defined in scope of A every time I log something. Sure I can wrap every single logger method (trace, info, debug ...) and add there session functionality but this will break line number.

I would do something like a static variable and a static setter in ContextFilter, but unfortunately I'm using using tornado (request are run in the same thread), which means I can't event use thread local context. Is filter the only workaround to get a custom variable for log entry?

Upvotes: 2

Views: 4482

Answers (2)

DataOrc
DataOrc

Reputation: 839

I actually used the Context Filter and it worked well for me. Here's a file I import (filters.py) which contains my Context filter:

import logging
from flask import request

class SessionFilter(logging.Filter):
    '''
    This class acts as a context filter for logs. If an action is executed as part of a request, this filter
    adds the session ID associated with the request to the log.
    '''

    def filter(self, record):
        try:
            record.session_id = request.headers['Cookie'].lstrip('session=')
        except:
            record.session_id = None
        return True

Upvotes: 1

deathangel908
deathangel908

Reputation: 9699

Just found the answer. I should use LoggingAdapter instead of Filter.

class A(object):

  def __init__(self):
    self.logger = logging.LoggerAdapter(log, {'session_id': random(1024)})

  def process(self):
    self.logger.info('hello')

Upvotes: 2

Related Questions