Why doesn't this Django logging work? - django

I'm having trouble getting going with Django logging. I've read both the Python and Django documentation on logging but I still don't see what I'm doing wrong. To start, I'm just trying to log a message to the console where my Django development server is running when I execute this simple view:
# demo/views.py
import logging
logger = logging.getLogger(__name__)
def demo_logging(request, template):
logger.error("Got some error")
return render(request, template)
I'm using Django's default logging setting as specified in django/utils/log.py in my settings file so that I (hopefully) know exactly what's happening (which, clearly I don't):
# settings.py
DEBUG = True
...
LOGGING_CONFIG = None
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',
},
'null': {
'class': 'logging.NullHandler',
},
'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'],
},
}
}
import logging.config
logging.config.dictConfig(LOGGING)
When I execute the view, I don't see anything in the console except the message,
No handlers could be found for logger "demo.views"
I don't understand what I'm doing wrong. I would think calling logger.error would hit the django logger which is linked to the console handler which is defined.
Thanks.
FOLLOW UP
I solved this problem by adding a default, "catch-all" logger that would be triggered when creating a logger using the "__name__" argument:
'loggers': {
'': {
'handlers': ['console'],
},
...

Calling logger = logging.getLogger(__name__) causes the logging module to search for a logger named as your module (demo.views); as you have no logger defined by that name, it fails. To simply log to console, you can use the django logger defined in 'loggers' key of your LOGGING configuration:
import logging
logger = logging.getLogger('django')
def demo_logging(request, template):
logger.error("Got some error")
return render(request, template)

Related

Use Logging SocketHandler with Django

I've configured my logging as so:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
'cute':{
'class': 'logging.handlers.SocketHandler',
'host': '127.0.0.1',
'port': 19996
},
},
'loggers': {
'django': {
'handlers': ['cute'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
},
},
}
But when I try and log out I get an error in the console:
TypeError: an integer is required (got type socket)
This seems to be happening within an attempt to pickle the log message, I think.
What is going on, and how can I get the SocketHandler to work?
There is a bug report about it. The request object cannot be pickled and the log fails.
My loggers were like yours before I got the same error as you did. Since my code contains apps that don't work with request, I partially fixed my problem creating a log for django.request without socket_handler
'django.request': {
'handlers': ['defaultfile', 'console'],
'level': 'WARNING',
'propagate': False,
},
However the bug report also suggest to create a custom SocketHandler removing request:
from logging.handlers import SocketHandler as _SocketHandler
class DjangoSocketHandler(_SocketHandler):
def emit(self, record):
if hasattr(record, 'request'):
record.request = None
return super().emit(record)
I haven't tried this yet, but it could be a way to go.

Django logging, log to file in development without needing to create the file in production

I'm implementing Django logging in a project. I've got it working such that log entries are inserted into a file in our dev environment, and into a database in our production environment.
The problem I'm having is that Django needs to create the log file, even though it will be empty, in non-dev environments.
Is there a better way to implement this so that the empty log file isn't created in non-dev environments?
My code:
settings.py logging configuration:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
},
'is_not_dev_environment': {
'()': 'lib.log.log.IsNotDevEnvironment'
},
'is_dev_environment': {
'()': 'lib.log.log.IsDevEnvironment'
}
},
'formatters': {
'standard': {
'format': "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
'datefmt': "%d/%b/%Y %H:%M:%S"
},
'custom': {
'format': CUSTOM_LOGGING_FORMAT,
'datefmt': "%d/%b/%Y %H:%M:%S"
},
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
},
'db': {
'level': LOGGING_LEVEL,
'filters': ['is_not_dev_environment'],
'class': 'lib.log.log.DBLogHandler',
'formatter': 'custom'
},
'file': {
'level': LOGGING_LEVEL,
'filters': ['is_dev_environment'],
'filename': /var/log/django.log,
'class': 'lib.log.log.FileLogHandler',
'formatter': 'custom',
},
},
'loggers': {
'django': {
'handlers': ['mail_admins'],
'level': LOGGING_LEVEL,
'propagate': True,
}
}
}
LOGGING['loggers'].update({app: copy.deepcopy(LOCAL_APP_LOGGER) for app in LOCAL_APPS})
lib/log/log.py which holds the filtering classes:
class IsNotDevEnvironment(logging.Filter):
def filter(self, record):
return settings.ENVIRONMENT != 'DEV'
class IsDevEnvironment(logging.Filter):
def filter(self, record):
return settings.ENVIRONMENT == 'DEV'
I settled on a different option that met my requirements. The main issue I was having was that in our test environment we couldn't create the log file (can't manipulate files with sudo on our CI provider's system). I resolved that by adding logic to disable logging based on an environment variable in the test environment.
tests/config.py:
from logging.config import dictConfigClass
from django.conf import settings
def logging_config(config):
disable_logging = getattr(settings, 'DISABLE_LOGGING', False)
if not disable_logging:
dictConfigClass(config).configure()
An alternative would be to set the handler based on some logic:
if ENVIRONMENT == 'DEV':
LOGGING['handlers'].update({
""" Dict specifying dev handler """
})
else:
LOGGING['handlers'].update({
""" Dict specifying production handler """
})

django logger can't output the response content

I'm use django 1.4.6, I want to use the logger module integrated with django to output the response content, however, I cannot see it in the log file.
Source sample shown here:
import logging
logger = logging.getLogger('__file__')
...
response = redirect(url)
logger.debug(response.content)
return response
Once you have configured your loggers, handlers, filters and formatters,
You need to call it as follows:
import logging
# Standard instance of a logger with __name__
stdlogger = logging.getLogger(__name__)
logger.debug(response.content)
response = redirect(url)
return response
The call to logging.getLogger() obtains (creating, if necessary) an instance of a logger. The logger instance is identified by a name. This name is used to identify the logger for configuration purposes.
By convention, the logger name is usually name .
The Python name syntax used for getLogger automatically assigns the package name as the logger name.
Please show peple configuration of logging in static file
I have little change for your code
logger = logging.getLogger(__name__)
Log configuation on settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': "[%(asctime)s] %(levelname)s %(message)s",
'datefmt': "%d/%b/%Y %H:%M:%S"
}
},
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': '/var/log/django_practices.log',
'formatter': 'verbose'
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'stream': sys.stdout,
'formatter': 'verbose'
},
},
'loggers': {
'name_your_app_django': {
'handlers': ['file', 'console'],
'level': ode'DEBUG',
}
}
}
In my configuration log will be print in console and file name.
Note : name_your_app_django change to fix with your code.

Why are assertions being logged in sentry when DEBUG = True?

I'm in the middle of deploying sentry to handle our django error messages. I've configured django's LOGGING settings to only log when DEBUG = False via the use of 'filters': ['require_debug_false'].
If I manually log an error in a django view as in the following example, it is successfully filtered and therefore not sent to sentry:
import logging
logger = logging.getLogger(__name__)
def view_name(request):
logger.error('An error message')
...
However, if I use an assert statement as in the following example, it is not filtered and does get sent to sentry:
import logging
logger = logging.getLogger(__name__)
def view_name(request):
assert False, 'An error message'
...
It is also worth noting that the assert statement does not get sent to the mail_admins handler, which also uses the same filter.
Can someone please help me prevent assert errors from begin sent to sentry whilst DEBUG = True?
Here are the package versions I am using:
Django==1.6.7
raven==5.1.1
And here are the relevant parts of my settings.py:
DEBUG = True
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'formatters': {
'simple': {
'format': '%(levelname)s %(asctime)s %(message)s'
},
},
'handlers': {
'console': {
'level': 'WARNING',
'filters': ['require_debug_false'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
},
'sentry': {
'level': 'WARNING',
'filters': ['require_debug_false'],
'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
},
},
'loggers': {
'': {
'handlers': ['console', 'mail_admins', 'sentry'],
'level': 'WARNING',
'propagate': False,
},
},
}
In raven-python 3.0.0 DEBUG setting in Django no longer disables Raven.
From documentation:
Raven to install a hook in Django that will automatically report
uncaught exceptions
In your case, assert generate uncaught exceptions AssertionError, which logged in Sentry.
To disable this functionality set dsn = None or remove dsn (source):
RAVEN_CONFIG = {
'dsn': None
}

How to use sentry/raven in django views

I managed to install sentry successfully and I can see the sentry interface webservice at localhost and doing a
raven test http://jsifslkdjfklsdfjklsdjfklMYCODE
works, the tests shows up in the interface.
The problem is I can't find any examples or documentation on what exactly should I put on my views and my settings.
I know I have to add to my INSTALLED_APPS
'sentry',
'raven.contrib.django',
And I also added
SENTRY_DNS = 'http://jsifslkdjfklsdfjklsdjfklMYCODE'
This next two lines appear in the docs but it doesnt say where do they go
from raven.contrib.django.models import client
client.captureException()
I tried in settings.py but still I can't get my views to log anything.
I also added this
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'root': {
'level': 'WARNING',
'handlers': ['sentry'],
},
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
},
'handlers': {
'sentry': {
'level': 'ERROR',
'class': 'raven.contrib.django.handlers.SentryHandler',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
}
},
'loggers': {
'django.db.backends': {
'level': 'ERROR',
'handlers': ['console'],
'propagate': False,
},
'raven': {
'level': 'DEBUG',
'handlers': ['console'],
'propagate': False,
},
'sentry.errors': {
'level': 'DEBUG',
'handlers': ['console'],
'propagate': False,
},
},
}
And in my views I added this:
import logging
logger = logging.getLogger()
def home(request,template_name):
logger.error('There was some crazy error lol', exc_info=True, extra={'request': request, })
return render_to_response(template_name,context, context_instance=RequestContext(request))
I have no other code related to logging apart from what you see here, What am I missing?
Your 'raven' logger is not actually using the sentry handler, but only writing to 'console'. Had the same problem. The documentation for raven/sentry lacks a good writer.
change your raven logger to:
'raven': {
'level': 'DEBUG',
'handlers': ['console', 'sentry'],
'propagate': False,
},
and make sure you use it as logger:
logger = logging.getLogger('raven')
I had to use this monstruosity on my settings.py:
import logging
# from raven.contrib.django.handlers import SentryHandler
from raven.handlers.logging import SentryHandler
logging.getLogger().setLevel(logging.INFO)
logger = logging.getLogger()# ensure we havent already registered the handler
handler = SentryHandler('http://13d06dad246d4fe6a180ef9b15151a13:eb46a6d724df4327a8cc04d9d3cfad37#sentry.bandtastic.pagekite.me/1')
logger.addHandler(handler)
# Add StreamHandler to sentry's default so you can catch missed exceptions
logger = logging.getLogger('sentry.errors')
logger.propagate = False
logger.addHandler(logging.StreamHandler())
from raven.conf import setup_logging
setup_logging(handler)
And in my views i can use a simple
import logging
logger = logging.getLogger(__name__)
def home(request,context={},template_name=None):
logger.info(str(request), exc_info=True)
return render_to_response(template_name,context, context_instance=RequestContext(request))
I tried many settings.