Django format email django errors - django

hi i would like create a format for django email errors, the email is automatic send by django in this case get the typical error format:
i would like get in the email report the project name, all type errors(404/500/etc)...
This is my settings:
ADMINS = (
('Diego Avila', 'diego.loachamin#test.com'),
)
#CONFIGURAR PARAMETROS EMAIL
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_SSL = True
EMAIL_HOST = 'mail.test.com'
EMAIL_HOST_USER = 'diego.loachamin#test.com'
EMAIL_HOST_PASSWORD = 'dsdsad'
EMAIL_PORT = 465
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
please someone suggest or idea.. thanks..!!

Django comes with such features built in. For 500 errors, it's a logging handler called AdminEmailHandler. It will trigger when there's uncaught exceptions, and will include the traceback in the email body.
404 is different. That's not an uncaught exception, but you can intercept those with BrokenLinkEmailsMiddleware and send emails.
To customize how these emails look, you can create your own subclass of either or both of AdminEmailHandler and BrokenLinkEmailsMiddleware. Change the relevant logging and middleware config in settings.py to point to your custom logging handler/middleware.
For the logging handler, you can for example use the format_subject method to add something to the subject line of the outgoing email.
class CustomAdminEmailHandler(AdminEmailHandler):
def format_subject(self, subject):
return '[ project name ]' + super().format_subject(subject)
Both the middleware and the logging handler uses django.core.email.mail-admins() to send the emails.

Related

Why my Django exception middleware does not log stack trace

I am trying to set up a custom exception handler.
# settings.py
LOGGING = {
// ...
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
},
},
'loggers': {
'django': {
'handlers': ['applogfile', 'mail_admins'],
'level': 'ERROR',
'propagate': True,
}
}
}
When I use the Django default exception handler and there is a Django error, I get an email containing the debug page, including the stack trace. However, I want to have my own exception middleware, so I added the following:
# middleware.py
from django.utils.deprecation import MiddlewareMixin
class MyExceptionMiddleware(MiddlewareMixin):
def process_exception(self, request, exception):
return render(request, template_name='error_message.html', context={
'title':'Error',
'message':'Sorry, we encountered an unexpected error'
})
# settings.py
MIDDLEWARE = [
# other middlewares
...
'middleware.MyExceptionMiddleware',
]
After I added this, the debug email that I get is missing the stack trace. It tells me that there is an "Internal server error" at the url, but it doesn't give any details of the errors.
I know I can override error handlers (https://docs.djangoproject.com/en/3.0/topics/http/views/#customizing-error-views) which would give me the full stack trace, but I am wondering why when I use a middleware to catch exceptions I don't get the stack trace.

Receive django error debug report by email :

Here is my configuration in django settings :
MAILER_LIST = ['toto#toto.com']
EMAIL_HOST = 'toto.smtp.com'
EMAIL_HOST_USER = 'toto#toto.com'
EMAIL_HOST_PASSWORD = 'tata'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'toto#toto.com'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'DEBUG',
'class': 'django.utils.log.AdminEmailHandler',
'filters': [],
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'DEBUG',
'propagate': True,
},
}
}
i've try to debug with :
from django.core.mail import EmailMessage
email = EmailMessage('Hello', 'World', to=['toto#toto.com'])
email.send()
And i get the test email if i put this in my settings.
i would like to receive this error report by email (it's just an example and i've added this error in my code to test the mail report) :
What am i missing to get the debug log by email ? The test is sending the email so it's not an email configuration problem ...
I would like to get the report by email and still show the debug page on django. And get the email event if debug is true or Not.
So i've set DEBUG = True in my settings.
Thanks and regards
As said in another answers if you want use django build-in AdminEmailHandler, then you need provide ADMINS and MANAGERS instead of MAILER_LIST in your settings.py. Like this:
ADMINS = ['toto#toto.com'] # better to use another mail than EMAIL_HOST_USER
MANAGERS = ADMINS
Django's utils.log have two options for processing your DEBUG value: RequireDebugFalse and RequireDebugTrue.
So if you want send error emails to your admins (ADMINS variable in settings.py) while debug, then you may use similar settings:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue' # log while DEBUG=True
}
},
'handlers': {
'debug_mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'filters': [require_debug_true],
}
},
'loggers': {
'django.request': {
'handlers': ['debug_mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
Upd.:
Also you can use logging.handlers.SMTPHandler. Then you can write something similar to this code: https://code.djangoproject.com/ticket/15917
Django handles this for you, you can add
MANAGERS = ['mail#mail.com']
or look into integrating sentry for a more robust error reporting, sentry is free too
You should use ADMINS:
ADMINS = ['notifications#example.com']
A list of all the people who get code error notifications. When DEBUG=False and AdminEmailHandler is configured in LOGGING (done by default), Django emails these people the details of exceptions raised in the request/response cycle.
More info here
Other than what has already been said in other answers, do not forget to set SERVER_EMAIL in your settings (docs).
It's the email address that error messages come from; it's similar to DEFAULT_FROM_EMAIL but SERVER_EMAIL is used only for error messages. Default value is 'root#localhost' and if you are using a provider like sendgrid your emails will be blocked.

How configure Django logging to file for app

I am struggling with Django logging configuration. I have one app called "api" and I want to save to file all logs from this app. When I set up a logger to django everything works fine but when I change it to my app_name it doesn't.
Here is my configuration:
File structure:
email_api
api
tasks.py
email_api
celery.py
settings
logs
email.log
My logging configuration:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': 'logs/email.log',
},
},
'loggers': {
'api': {
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
},
}
tasks.py file where I logging:
import logging
logger = logging.getLogger(__name__)
#app.task(bind=True, default_retry_delay=3, max_retries=3,)
def send_email(self, data, email_id):
message = create_message(data, email)
try:
logger.debug("Log Message Here")
message.send()
Keys in the LOGGING['loggers'][...] dict are names of loggers. You have configured logging with api as a name of the logger.
In order to write to this logger, you should request it by that name:
logger = logging.getLogger('api')
...
logger.debug("Log Message Here")

django: How can I create a custom Logging Filter for SuspiciousOperation exception?

After migrate to 1.11 ( from 1.8 ) I'm receiving some SuspiciousOperation errors from logging.
It seems it comes from JS request who keeps session alive if user move their mouse. But this is not important.
How can I filter just this exception?
What I tried:
I just created a filter somewhere:
import logging
from django.core.exceptions import SuspiciousOperation
class StopSuspiciousOperation(logging.Filter):
def filter(self, record):
if record.exc_info:
exc_value = record.exc_info[1]
return isinstance(exc_value, SuspiciousOperation)
return True
Then I added this filter to my configuration:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
'stop_suspicious_operation': {
'()': 'aula.utils.loggingFilters.StopSuspiciousOperation',
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false',
'stop_suspicious_operation',], #<-- here
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
But I'm still receiving the error:
Internal Server Error: /keepalive
SuspiciousOperation at /keepalive
The request's session was deleted before the request completed. The user may have logged out in a concurrent request, for example.
Request Method: GET
Request URL: https://XXXXXX/YYYYYY
Django Version: 1.11.9
Python Executable: /usr/bin/python
Python Version: 2.7.3
I am not sure about the correct answer, but I think django is catching the SuspiciousOperation at WSGI level and is logging an ERROR. See:
https://docs.djangoproject.com/en/dev/ref/exceptions/#suspiciousoperation
If a SuspiciousOperation exception reaches the WSGI handler level it
is logged at the Error level and results in a HttpResponseBadRequest.
You maybe just want to filter out the bad requests like this:
from logging import LogRecord
def filter_400(record: LogRecord) -> bool:
'''Filter out HTTP Error Code 400 Bad Request'''
return record.status_code != 400

django.request logger not working for get_object_or_404

I have this code for UserDetailsView in Django Rest Framework. I am using django 1.9 and DRF 3.
class UserDetailsView(RetrieveUpdateAPIView):
"""
API endpoint that allows a user to be viewed or edited.
"""
serializer_class = UserDetailsSerializer
permission_classes = (IsAuthenticated,)
def get_object(self):
pk = self.kwargs.get('pk', None)
if not pk or (pk == str(self.request.user.pk)):
return self.request.user
else:
try:
return get_object_or_404(User, id=pk)
except ValueError:
return get_object_or_404(User, username=pk)
I have have my django logger configured as per these settings.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '[%(levelname)s] %(message)s'
},
},
'handlers': {
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'logs/backend_common.log',
'maxBytes': 1024*1024*10,
'backupCount': 10,
'formatter': 'simple',
},
'request_handler': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'logs/backend_requests.log',
'maxBytes': 1024*1024*10,
'backupCount': 10,
'formatter': 'simple',
},
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
}
},
'loggers': {
'': {
'handlers': ['default'],
'propagate': True,
},
'django.request': {
'handlers': ['request_handler', 'mail_admins'],
'level': 'DEBUG',
'propagate': False,
}
}
}
Now, all django 4xx, 5xx error status code should ideally be logged into backend_requests.log file and they are except 404 status resulting from get_object_or_404. I think 404 errors resulting from this view should also get logged. Any help is highly appreciated.
There are actually two issues here.
The first is a bug in Django, which was fixed just a few days ago. The bit of code that was logging 404s was running a little too early. The next release of Django will work and your 404s will be logged as you would expect.
For other exceptions however, the problem is as follows. Django will log errors if the exceptions that caused them are bubbled up to the core request handler. However if the view or some middleware catches the exception and handles it, then this portion of Django's code never gets called. This is what is happening with DRF:
REST framework's views handle various exceptions, and deal with returning appropriate error responses.
The handled exceptions are:
Subclasses of APIException raised inside REST framework.
Django's Http404 exception.
Django's PermissionDenied exception.
In each case, REST framework will return a response with an appropriate status code and content-type. The body of the response will include any additional details regarding the nature of the error.
Because DRF catches the exception and returns a response object to Django, Django will just render the response and not log the error. This makes sense - it is possible for some middleware to take what was originally a 404 but return a different response instead (the flatpage middleware is a good example).
If you want to log exceptions handled by DRF you can specify your own EXCEPTION_HANDLER in the DRF config, or write your own middleware that logs the errors.
Note that 5xx exceptions are not handled by DRF and these should still propagate up to Django. These should be getting logged for you even now.