mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from __future__ import unicode_literals
 | |
| 
 | |
| import logging
 | |
| import sys
 | |
| import warnings
 | |
| 
 | |
| from django.conf import settings
 | |
| from django.core import mail
 | |
| from django.core.mail import get_connection
 | |
| from django.utils.deprecation import RemovedInNextVersionWarning
 | |
| from django.utils.encoding import force_text
 | |
| from django.utils.module_loading import import_string
 | |
| from django.views.debug import ExceptionReporter, get_exception_reporter_filter
 | |
| 
 | |
| # Default logging for Django. This sends an email to the site admins on every
 | |
| # HTTP 500 error. Depending on DEBUG, all other log records are either sent to
 | |
| # the console (DEBUG=True) or discarded by mean of the NullHandler (DEBUG=False).
 | |
| DEFAULT_LOGGING = {
 | |
|     'version': 1,
 | |
|     'disable_existing_loggers': False,
 | |
|     'filters': {
 | |
|         'require_debug_false': {
 | |
|             '()': 'django.utils.log.RequireDebugFalse',
 | |
|         },
 | |
|         'require_debug_true': {
 | |
|             '()': 'django.utils.log.RequireDebugTrue',
 | |
|         },
 | |
|     },
 | |
|     'handlers': {
 | |
|         'console': {
 | |
|             'level': 'INFO',
 | |
|             'filters': ['require_debug_true'],
 | |
|             'class': 'logging.StreamHandler',
 | |
|         },
 | |
|         'mail_admins': {
 | |
|             'level': 'ERROR',
 | |
|             'filters': ['require_debug_false'],
 | |
|             'class': 'django.utils.log.AdminEmailHandler'
 | |
|         }
 | |
|     },
 | |
|     'loggers': {
 | |
|         'django': {
 | |
|             'handlers': ['console'],
 | |
|         },
 | |
|         'django.request': {
 | |
|             'handlers': ['mail_admins'],
 | |
|             'level': 'ERROR',
 | |
|             'propagate': False,
 | |
|         },
 | |
|         'django.security': {
 | |
|             'handlers': ['mail_admins'],
 | |
|             'level': 'ERROR',
 | |
|             'propagate': False,
 | |
|         },
 | |
|         'py.warnings': {
 | |
|             'handlers': ['console'],
 | |
|         },
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| def configure_logging(logging_config, logging_settings):
 | |
|     if not sys.warnoptions:
 | |
|         # Route warnings through python logging
 | |
|         logging.captureWarnings(True)
 | |
|         # RemovedInNextVersionWarning is a subclass of DeprecationWarning which
 | |
|         # is hidden by default, hence we force the "default" behavior
 | |
|         warnings.simplefilter("default", RemovedInNextVersionWarning)
 | |
| 
 | |
|     if logging_config:
 | |
|         # First find the logging configuration function ...
 | |
|         logging_config_func = import_string(logging_config)
 | |
| 
 | |
|         logging.config.dictConfig(DEFAULT_LOGGING)
 | |
| 
 | |
|         # ... then invoke it with the logging settings
 | |
|         if logging_settings:
 | |
|             logging_config_func(logging_settings)
 | |
| 
 | |
| 
 | |
| class AdminEmailHandler(logging.Handler):
 | |
|     """An exception log handler that emails log entries to site admins.
 | |
| 
 | |
|     If the request is passed as the first argument to the log record,
 | |
|     request data will be provided in the email report.
 | |
|     """
 | |
| 
 | |
|     def __init__(self, include_html=False, email_backend=None):
 | |
|         logging.Handler.__init__(self)
 | |
|         self.include_html = include_html
 | |
|         self.email_backend = email_backend
 | |
| 
 | |
|     def emit(self, record):
 | |
|         try:
 | |
|             request = record.request
 | |
|             subject = '%s (%s IP): %s' % (
 | |
|                 record.levelname,
 | |
|                 ('internal' if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS
 | |
|                  else 'EXTERNAL'),
 | |
|                 record.getMessage()
 | |
|             )
 | |
|             filter = get_exception_reporter_filter(request)
 | |
|             request_repr = '\n{}'.format(force_text(filter.get_request_repr(request)))
 | |
|         except Exception:
 | |
|             subject = '%s: %s' % (
 | |
|                 record.levelname,
 | |
|                 record.getMessage()
 | |
|             )
 | |
|             request = None
 | |
|             request_repr = "unavailable"
 | |
|         subject = self.format_subject(subject)
 | |
| 
 | |
|         if record.exc_info:
 | |
|             exc_info = record.exc_info
 | |
|         else:
 | |
|             exc_info = (None, record.getMessage(), None)
 | |
| 
 | |
|         message = "%s\n\nRequest repr(): %s" % (self.format(record), request_repr)
 | |
|         reporter = ExceptionReporter(request, is_email=True, *exc_info)
 | |
|         html_message = reporter.get_traceback_html() if self.include_html else None
 | |
|         self.send_mail(subject, message, fail_silently=True, html_message=html_message)
 | |
| 
 | |
|     def send_mail(self, subject, message, *args, **kwargs):
 | |
|         mail.mail_admins(subject, message, *args, connection=self.connection(), **kwargs)
 | |
| 
 | |
|     def connection(self):
 | |
|         return get_connection(backend=self.email_backend, fail_silently=True)
 | |
| 
 | |
|     def format_subject(self, subject):
 | |
|         """
 | |
|         Escape CR and LF characters, and limit length.
 | |
|         RFC 2822's hard limit is 998 characters per line. So, minus "Subject: "
 | |
|         the actual subject must be no longer than 989 characters.
 | |
|         """
 | |
|         formatted_subject = subject.replace('\n', '\\n').replace('\r', '\\r')
 | |
|         return formatted_subject[:989]
 | |
| 
 | |
| 
 | |
| class CallbackFilter(logging.Filter):
 | |
|     """
 | |
|     A logging filter that checks the return value of a given callable (which
 | |
|     takes the record-to-be-logged as its only parameter) to decide whether to
 | |
|     log a record.
 | |
| 
 | |
|     """
 | |
|     def __init__(self, callback):
 | |
|         self.callback = callback
 | |
| 
 | |
|     def filter(self, record):
 | |
|         if self.callback(record):
 | |
|             return 1
 | |
|         return 0
 | |
| 
 | |
| 
 | |
| class RequireDebugFalse(logging.Filter):
 | |
|     def filter(self, record):
 | |
|         return not settings.DEBUG
 | |
| 
 | |
| 
 | |
| class RequireDebugTrue(logging.Filter):
 | |
|     def filter(self, record):
 | |
|         return settings.DEBUG
 |