Created
April 14, 2016 07:40
-
-
Save countermeasure/3aa795b70931797789a7dc85f6858db0 to your computer and use it in GitHub Desktop.
Django logging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add this to your common app in a file called `backends.py` | |
from logging import getLogger | |
from django.core.mail.backends.filebased import EmailBackend as FBEmailBackend | |
from django.core.mail.backends.smtp import EmailBackend as SmtpEmailBackend | |
class LoggingFileBasedEmailBackend(FBEmailBackend): | |
"""A wrapper around ``filebased.EmailBackend`` that logs every email. | |
The ``write_message`` function is is duplicate of the matching function in | |
``filebased.EmailBackend``, but with some logging added.""" | |
def __init__(self, *args, **kwargs): | |
super(LoggingFileBasedEmailBackend, self).__init__(*args, **kwargs) | |
self.logger = getLogger('django.mail') | |
def write_message(self, message): | |
self.stream.write(message.message().as_bytes() + b'\n') | |
self.stream.write(b'-' * 79) | |
self.stream.write(b'\n') | |
log_entry = 'Recipient: %s | Subject: \'%s\' | Status: Sent' % ( | |
'; '.join(message.recipients()), | |
message.subject, | |
) | |
self.logger.info(log_entry) | |
class LoggingSmtpEmailBackend(SmtpEmailBackend): | |
"""A wrapper around ``smtp.EmailBackend`` that logs every email. The | |
``send_messages`` function is a duplicate of the matching function in | |
``smtp.EmailBackend``, but with some logging added.""" | |
def __init__(self, *args, **kwargs): | |
super(LoggingSmtpEmailBackend, self).__init__(*args, **kwargs) | |
self.logger = getLogger('django.mail') | |
def send_messages(self, email_messages): | |
if not email_messages: | |
return | |
with self._lock: | |
new_conn_created = self.open() | |
if not self.connection: | |
# We failed silently on open(). | |
# Trying to send would be pointless. | |
return | |
num_sent = 0 | |
for message in email_messages: | |
sent = self._send(message) | |
log_entry = 'Recipient: %s | Subject: \'%s\'' % ( | |
'; '.join(message.recipients()), | |
message.subject, | |
) | |
if sent: | |
num_sent += 1 | |
log_entry += ' | Status: Sent' | |
self.logger.info(log_entry) | |
else: | |
log_entry += ' | Status: Failed to send' | |
self.logger.warn(log_entry) | |
if new_conn_created: | |
self.close() | |
return num_sent |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add this to your authentication app in a file called `loggers.py` | |
from logging import getLogger | |
logger = getLogger('django.events') | |
def log_successful_login(user): | |
"""Logs a successful login.""" | |
logger.info( | |
'User \'%s\' (id: %s) logged in.' % ( | |
user.get_full_name(), | |
user.pk, | |
) | |
) | |
def log_failed_login_attempt(subdomain, email): | |
"""Logs a failed attempt to login.""" | |
logger.warning( | |
'Failed login attempt with email \'%s\'.' % email | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add this to your common app in a file called `middleware.py` | |
import json | |
from logging import getLogger | |
class LoggingMiddleware(object): | |
"""Middleware to log every request.""" | |
def __init__(self): | |
self.logger = getLogger('django.all_requests') | |
def process_string(self, key, obj): | |
"""Accepts a key and an object. | |
If the object is a string longer than 100 characters, truncates it. | |
If the object looks like a password or is a CSRF token, omits it.""" | |
if isinstance(obj, basestring): | |
if ( | |
'password' in key.lower() or | |
key.lower() == 'csrfmiddlewaretoken' | |
): | |
return '**omitted**' | |
else: | |
return '%s...' % obj[:100] if len(obj) > 100 else obj | |
else: | |
return object | |
def process_request(self, request): | |
log_entry = 'User: %s -- %s -- %s' % ( | |
request.user.pk, | |
request.method, | |
request.build_absolute_uri(), | |
) | |
# Include data from POST or PUT requests in the log entry. | |
if request.method in ('POST', 'PUT'): | |
log_entry += ' -- ' | |
# Handle form data. | |
if request.POST: | |
request_string = '{' | |
for key, value in request.POST.iteritems(): | |
request_string += ( | |
'%s: \'%s\', ' % (key, self.process_string(key, value)) | |
) | |
request_string = '%s%s' % (request_string[0: -2], '}') | |
log_entry += request_string | |
# Handle json data from the API. | |
else: | |
api_data = json.loads(request.body) | |
for key, value in api_data.iteritems(): | |
api_data[key] = self.process_string(key, value) | |
log_entry += json.dumps(api_data) | |
self.logger.info(log_entry) | |
return None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add this to your `settings.py` | |
# Logging | |
# https://docs.djangoproject.com/en/1.9/topics/logging/ | |
if ENVIRONMENT == 'development': | |
LOG_DIR = os.path.join(BASE_DIR, 'media', 'logs/') | |
else: | |
LOG_DIR = '/home/econvenor/logs_django/' | |
LOGGING = { | |
'version': 1, | |
'disable_existing_loggers': False, | |
'formatters': { | |
'basic': { | |
'format': '[%(asctime)s] -- %(message)s', | |
}, | |
'events': { | |
'format': '[%(asctime)s] %(levelname)s -- %(message)s', | |
}, | |
}, | |
'handlers': { | |
'all_requests': { | |
'level': 'INFO', | |
'class': 'logging.FileHandler', | |
'filename': os.path.join(LOG_DIR, 'all_requests.log'), | |
'formatter': 'basic', | |
}, | |
'events': { | |
'level': 'INFO', | |
'class': 'logging.FileHandler', | |
'filename': os.path.join(LOG_DIR, 'events.log'), | |
'formatter': 'events', | |
}, | |
'mail': { | |
'level': 'INFO', | |
'class': 'logging.FileHandler', | |
'filename': os.path.join(LOG_DIR, 'mail.log'), | |
'formatter': 'events', | |
}, | |
}, | |
'loggers': { | |
'django.all_requests': { | |
'handlers': ['all_requests'], | |
'level': 'INFO', | |
'propagate': True, | |
}, | |
'django.events': { | |
'handlers': ['events'], | |
'level': 'INFO', | |
'propagate': True, | |
}, | |
'django.mail': { | |
'handlers': ['mail'], | |
'level': 'INFO', | |
'propagate': True, | |
}, | |
}, | |
} | |
# Email settings | |
if ENVIRONMENT == 'development': | |
EMAIL_BACKEND = 'common.backends.LoggingFileBasedEmailBackend' | |
else: | |
EMAIL_BACKEND = 'common.backends.LoggingSmtpEmailBackend' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add this to `views.py` in your authentication app | |
from django.contrib.auth import ( | |
authenticate, | |
login, | |
) | |
from django.shortcuts import ( | |
redirect, | |
render, | |
) | |
from .loggers import ( | |
log_failed_login_attempt, | |
log_successful_login, | |
) | |
def user_login(request): | |
""" | |
Logs a user in. | |
""" | |
if request.method == 'POST': | |
email = request.POST['email'].lower() | |
password = request.POST['password'] | |
user = authenticate(email=email, password=password) | |
if user is not None: | |
if user.is_active: | |
login(request, user) | |
log_successful_login(user) | |
return redirect('accounts-dash') | |
else: | |
error = 'Your account is not active.' | |
else: | |
log_failed_login_attempt(email) | |
error = 'The credentials you entered are not valid. Try again.' | |
return render(request, 'user_login.html', {'error': error}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment