123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- import os
- import logging
- import json
- from pathlib import Path
- from django.http import HttpRequest
- BUILDDIR = Path(os.environ.get('BUILDDIR', '/tmp'))
- def log_api_request(request, response, view, logger_name='api'):
- """Helper function for LogAPIMixin"""
- repjson = {
- 'view': view,
- 'path': request.path,
- 'method': request.method,
- 'status': response.status_code
- }
- logger = logging.getLogger(logger_name)
- logger.info(
- json.dumps(repjson, indent=4, separators=(", ", " : "))
- )
- def log_view_mixin(view):
- def log_view_request(*args, **kwargs):
- # get request from args else kwargs
- request = None
- if len(args) > 0:
- for req in args:
- if isinstance(req, HttpRequest):
- request = req
- break
- elif request is None:
- request = kwargs.get('request')
- response = view(*args, **kwargs)
- view_name = 'unknown'
- if hasattr(request, 'resolver_match'):
- if hasattr(request.resolver_match, 'view_name'):
- view_name = request.resolver_match.view_name
- log_api_request(
- request, response, view_name, 'toaster')
- return response
- return log_view_request
- class LogAPIMixin:
- """Logs API requests
- tested with:
- - APIView
- - ModelViewSet
- - ReadOnlyModelViewSet
- - GenericAPIView
- Note: you can set `view_name` attribute in View to override get_view_name()
- """
- def get_view_name(self):
- if hasattr(self, 'view_name'):
- return self.view_name
- return super().get_view_name()
- def finalize_response(self, request, response, *args, **kwargs):
- log_api_request(request, response, self.get_view_name())
- return super().finalize_response(request, response, *args, **kwargs)
- LOGGING_SETTINGS = {
- 'version': 1,
- 'disable_existing_loggers': False,
- 'filters': {
- 'require_debug_false': {
- '()': 'django.utils.log.RequireDebugFalse'
- }
- },
- 'formatters': {
- 'datetime': {
- 'format': '%(asctime)s %(levelname)s %(message)s'
- },
- 'verbose': {
- 'format': '{levelname} {asctime} {module} {name}.{funcName} {process:d} {thread:d} {message}',
- 'datefmt': "%d/%b/%Y %H:%M:%S",
- 'style': '{',
- },
- 'api': {
- 'format': '\n{levelname} {asctime} {name}.{funcName}:\n{message}',
- 'style': '{'
- }
- },
- 'handlers': {
- 'mail_admins': {
- 'level': 'ERROR',
- 'filters': ['require_debug_false'],
- 'class': 'django.utils.log.AdminEmailHandler'
- },
- 'console': {
- 'level': 'DEBUG',
- 'class': 'logging.StreamHandler',
- 'formatter': 'datetime',
- },
- 'file_django': {
- 'level': 'INFO',
- 'class': 'logging.handlers.TimedRotatingFileHandler',
- 'filename': BUILDDIR / 'toaster_logs/django.log',
- 'when': 'D', # interval type
- 'interval': 1, # defaults to 1
- 'backupCount': 10, # how many files to keep
- 'formatter': 'verbose',
- },
- 'file_api': {
- 'level': 'INFO',
- 'class': 'logging.handlers.TimedRotatingFileHandler',
- 'filename': BUILDDIR / 'toaster_logs/api.log',
- 'when': 'D',
- 'interval': 1,
- 'backupCount': 10,
- 'formatter': 'verbose',
- },
- 'file_toaster': {
- 'level': 'INFO',
- 'class': 'logging.handlers.TimedRotatingFileHandler',
- 'filename': BUILDDIR / 'toaster_logs/web.log',
- 'when': 'D',
- 'interval': 1,
- 'backupCount': 10,
- 'formatter': 'verbose',
- },
- },
- 'loggers': {
- 'django.request': {
- 'handlers': ['file_django', 'console'],
- 'level': 'WARN',
- 'propagate': True,
- },
- 'django': {
- 'handlers': ['file_django', 'console'],
- 'level': 'WARNING',
- 'propogate': True,
- },
- 'toaster': {
- 'handlers': ['file_toaster'],
- 'level': 'INFO',
- 'propagate': False,
- },
- 'api': {
- 'handlers': ['file_api'],
- 'level': 'INFO',
- 'propagate': False,
- }
- }
- }
|