user3516853
user3516853

Reputation: 71

Retrieving the request object in a custom Django logging handler

I have a custom Logging handler that I want to handle all logging message levels (INFO, WARN, DEBUG, ERROR, etc.) and send that to a data analytics server. For each message, the data will include fields on the record and on the original request object.

The problem is that I have not seen the request object attached to any of the records. I found on the official documentation that only django.request messages have the request object attached to the record, but no mention of what specifically django.request messages are. (https://docs.djangoproject.com/en/1.9/topics/logging/#django-request).

What are django.request messages? How/When are they fired? How can I reroute every logging message to have the request object on it so that my handler can attach that data that will be sent to a proxy server?

----handler----

class LogHandler(logging.Handler):
    request = None

    def __init__(self, request=None):
        logging.Handler.__init__(self)

    def parse_record_to_json(self, record):
        import json

        created = datetime.datetime.fromtimestamp(record.created)
        return {
            'timestamp': created.strftime('%m/%d/%Y %H:%M:%S'),
            'method': record.funcName,
            'level': record.levelname,
            'line': record.lineno,
            'module': record.module,
            'message': record.getMessage(),
            'path': record.pathname,
        }

    def emit(self, record):
        user_id = None
        try:
            self.request = record.request
            if self.request.user.is_authenticated():
                user_id = self.request.user.id
        except:
            print "this must not be a django.request message"
            self.request = None

        from .event import SendEvent
        json_record = self.parse_record_to_json(record)
        level = json_record.pop('level', None)

        SendEvent(key="server_log",
                    name=level,
                    request=self.request,
                    obj=json_record,
                    user=user_id)

-----settings.py-----

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': '%(levelname)s  %(name)s  %(asctime)s %(filename)s:%(lineno)s] %(message)s',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'standard',
        },
        'null': {
            'level': 'DEBUG',
            'class': 'django.utils.log.NullHandler',
        },
        'splunk':{
            'class':'proj.common.handlers.LogHandler',

        }
    },
    # 'root': {
    #     'handlers': ['console', 'loghandler',],
    #     'level': 'INFO',
    #     'formatter':'standard',
    # },
    'loggers': {
        'django':{
            'handlers':['console'],
            'level':'INFO',
            'formatter':'standard',
        },
        'py.warnings':{
            'handlers': ['null',],
            'propagate': False,
        },
        'django.request':{
            'handlers':['console','loghandler'],
            'propogate':False,
        },
    }
}

Upvotes: 7

Views: 2857

Answers (1)

bignose
bignose

Reputation: 32307

To answer the “what is a django.request message”: The django.request logger is one of the Python loggers provided with Django. So, a django.request message is a log message sent to the django.request logger. As you've found, the Django documentation says:

Messages to this logger have the following extra context:

  • status_code: The HTTP response code associated with the request.
  • request: The request object that generated the logging message.

What may not be obvious is that “extra context” is provided with the logging message, and those items become attributes on the LogRecord instance.

So yes, in the LogHandler.emit method you defined, the record parameter is the LogRecord. The record.request attribute will be the HTTP request object, if the record was created on the django.request logger.

Your LogHandler will only receive messages if you direct them there, for example via the Django setting LOGGING['loggers']['django.request']['handlers'].

Upvotes: 2

Related Questions