""" logger decorator to enable logging of infos from django's HttpRequest object. Usage: Code: @log.logger(__name__) def home(request, logger=None): logger.info('user performed some action') Class based views work the same way, just decorate/modify the view's METHOD(s). Logging formatter configuration: 'format': '[%(asctime)s] %(levelname)s %(message)s ' \ '[ip: %(request.META.REMOTE_ADDR)s, ua: "%(request.META.HTTP_USER_AGENT)s"]' Based on code from (but heavily modified/refactored): https://derrickpetzold.com/p/django-requst-logging-json/ which is (c) Derrick Petzold - with a Creative Commons BY-SA license. """ import logging from django.http.request import HttpRequest def _get_attrdict(obj, basename, excluded=None): """ get a dictionary of (basename-prefixed) attribute names/values, excluding the excluded names, internal stuff and callables. :param obj: the object to inspect :param basename: the prefix for the names in the result dictionary :param excluded: excluded attribute names, do not even touch [set or list] :return: dict names: values """ if excluded is None: excluded = set() d = {} names = set(dir(obj)) - set(excluded) for name in names: if not name.startswith('_'): try: attr = getattr(obj, name) if not callable(attr): d[basename + name] = attr except AttributeError: pass return d def _get_elementdict(dct, basename, excluded=None): """ get a dictionary of (basename-prefixed) dictionary elements, excluding the excluded names. :param dct: the dict to inspect :param basename: the prefix for the names in the result dictionary :param excluded: excluded dictionary keys [set or list] :return: dict names: values """ if excluded is None: excluded = set() names = set(dct) - set(excluded) return {basename + name: dct[name] for name in names} def _build_request_info(request): """ build a dictionary with extra information extracted from request object :param request: django HttpRequest object :return: dict names: values """ d = _get_elementdict(request.META, "request.META.") d.update(_get_attrdict(request, "request.", ['raw_post_data', ])) d.update(_get_attrdict(request.session, "request.session.")) d.update(_get_attrdict(request.user, "request.user.")) return d def logger(name): """ decorator to provide extra information from request to logging :param name: name of the logger :return: decorated function/method """ def wrap(func): def caller(*args, **kwargs): request = None for arg in args: if isinstance(arg, HttpRequest): request = arg break if 'logger' not in kwargs: l = logging.getLogger(name) if request is None: kwargs['logger'] = l else: kwargs['logger'] = logging.LoggerAdapter(l, _build_request_info(request)) return func(*args, **kwargs) return caller return wrap