Django logging set up
来源:互联网 发布:有限元软件开发工程师 编辑:程序博客网 时间:2024/06/05 01:17
转载自:https://www.webforefront.com/django/setupdjangologging.html
红底部分是我的note,目前估计是因为dango版本的原因导致有些信息有误,等搜集到更多的信息后,再整理这个blog
Django logging set up
Problem
You want to set up Django logging to debug a project's workflow or detect potential errors.
Solution
Set up loggers in your Django project files using the getLogger
method of the Python logging
package. Next, define logging messages with one of several logger methods: <logger_name>.critical()
, <logger_name>.error()
, <logger_name>.warning()
, <logger_name>.info()
or <logger_name>.debug()
.
Configure the LOGGING
variable in settings.py
to process logging messages from your loggers. Set up different handlers in the LOGGING
variable to send logging messages to different destinations (e.g. console, file, email). Set up a logging level in either the loggers or handlers section of the LOGGING
variable to establish a logging threshold. Optionally set up filters in the LOGGING
variable to further refine the type of logging messages that get reported. Optionally set up formatters in the LOGGING
variable to customize the final logging output.
How it works
Python core logging concepts
Django is built on top of Python's logging package. The Python logging package provides a robust and flexible way to setup application logging. In case you've never used Python's logging package, I'll provide a brief overview of its core concepts. There are four core concepts in Python logging:
- Loggers.- Provide the initial entry point to group logging messages. Generally, each Python module (i.e.
.py
file) has a single logger to assign its logging messages. However, it's also possible to define multiple loggers in the same module (e.g. one logger for business logic, another logger for database logic,etc). In addition, it's also possible to use the same logger across multiple Python modules or.py
files. - Handlers.- Are used to redirect log messages (created by loggers) to a destination. Destinations can include flat files, a server's console, an email or SMS messages, among other destinations. It's possible to use more than one handler for the same logger.
- Filters.- Offer a way to apply fine grained rules on certain logging messages. For example, you can filter logging messages generated by the same logger but on different methods and send them to different handlers.
- Formatters.- Are used to specify the final format for log messages.
With this brief overview of Python logging concepts, let's jump straight into exploring Django's default logging functionality.
Exploring how Django's default logging works
The logging configuration for Django projects is defined in the LOGGING
variable in settings.py
. For the moment, don't even bother opening your project's settings.py
file because you won't see LOGGING
in it. This variable isn't hard-coded when you create a project, but it does have some logging values in effect if it isn't declared. Listing 1 shows the default LOGGING
values if it isn't declared in settings.py
.
Listing 1 - Default LOGGING in Django projects
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'], }, }}
n summary, the default Django logging settings illustrated in listing 1 have the following logging behaviors:
- Console logging or the
console
handler will only be done whenDEBUG=True
, for logging messages worse thanINFO
(inclusive) and only for the Python packagedjango
-- and its childrendjango.request
,django.contrib
,etc -- as well as the Python packagepy.warnings
. - Admin logging or the
mail_admins
handler -- which sends emails toADMINS
-- will only be done whenDEBUG=False
, for logging messages worse thanERROR
(inclusive) and only for the Python packagesdjango.request
anddjango.security
.
Now lets break down the
handlers
section in listing 1. Handlers define locations to send logging messages and there are three in listing 1: console
, null
and mail_admins
. The handler names by themselves do nothing -- they are simply reference names -- the relevant actions are defined in the associated properties dictionary. All the handlers have a class
property which defines the backing Python class that does the actual work.The
console
handler is assigned the logging.StreamHandler
class which is part of the core Python logging package. This class sends logging output to streams such as standard input and standard error, which as the handler name suggests is technically the system console or screen where Django runs. The null
handler is assigned the logging.NullHandler
class which is also part of the core Python logging package and which generates no output. And the mail_admins
handler is assigned the django.utils.log.AdminEmailHandler
class that is a Django custom handler utility, which sends logging output as an email to people defined as ADMINS
in settings.py
-- see the previous recipe Django settings.py for the real world: Security, absolute paths and multiple environments/files for more information on the ADMINS
variable.Another property in Django handlers is level
which defines the threshold level at which the handler will accept logging messages. There are five threshold levels for Python logging, from worst to least worst they are: CRITICAL
, ERROR
, WARNING
, INFO
and DEBUG
. The INFO
level for the console
handler indicates that all logging messages worse or equal to INFO
-- which is every level, except DEBUG
-- will make it to the handler, a reasonable setting as the console can handle many messages. The ERROR
level for the mail_admins
handler indicates that only messages worse or equal to ERROR
-- which is just CRITICAL
-- will make it to the handler, a reasonable setting as only the two worst types of error messages will trigger emails to administrators.
The other property in Django handlers is filters
which defines an additional layer to restrict logging messages for a handler. Handlers can accept multiple filters, which is why the filters
property accepts a Python list. The console
handler has a single filter require_debug_true
and the mail_admins
handler has a single filter require_debug_false
. Filters are defined in their own block as you can observe in listing 1. The require_debug_false
filter is backed by the django.utils.log.RequireDebugFalse
class which checks if a project has DEBUG=False
, where as the require_debug_true
filter is backed by the django.utils.log.RequireDebugTrue
class which checks if a project has DEBUG=True
. This means the console
handler will only accept logging messages if a Django project has DEBUG=True
and the mail_admins
handler will only accept logging messages if a Django project has DEBUG=False
.
Now that you understand handlers
and filters
, lets take a look at loggers
. Logger definitions generally map directly to Python packages and have parent-child relationships. For example, Python modules (i.e. .py
files) that belong to a package named coffeehouse
will generally have a logger named coffeehouse
and Python modules that belong to the package coffeehouse.about
will generally have a logger named coffeehouse.about
. The dot notation in logger names also represents a parent-child relationship, so the coffeehouse.about
logger is considered the child of the coffeehouse
logger.
In listing 1 there are four loggers: django
, django.request
, django.security
and py.warnings
. The django
logger indicates that all logging messages associated with it and its children be processed by the console
handler.
django.request
logger indicates that all logging messages associated with it and its children be processed by the mail_admins
handler. The django.request
logger also has the 'level':'ERROR'
property to provide the threshold level at which the logger will accept logging messages -- a property that overrides the handler level
property. And in addition, the django.request
logger also has the 'propagate':'False'
to indicate the logger should not propagate messages to parent loggers (e.g. django
is the parent of django.request
).Next, we have the django.security
logger which is identical in functionality to the django.request
logger. And the py.warnings
which indicates that all logging messages associated with it and its children be processed by the console
handler.
Finally there are the first two lines in listing 1 which are associated with Python logging in general. The version
key identifies the configuration version as 1
, which at present is the only Python logging version. And the disable_existing_loggers
key is used to disable all existing Python loggers. If disable_existing_loggers
is False
it keeps the pre-existing logger values and if it's set to True
it disables all pre-existing loggers values. Note that if you use 'disable_existing_loggers': False
in your own LOGGING
variable you can redefine/override some or all of the pre-existing logger values.
Now that you have a firm understanding of what Django logging does in its default state, I'll describe how to create logging messages in a Django project and finish the recipe with a custom LOGGING
configuration.
Create logging messages in a Django project
At the top of any Python module or .py
file you can create loggers by using the getLogger
method of the logging
package. The getLogger
method receives the name of the logger as its input parameter. Listing 2 illustrates the creation of two logger instances using __name__
and the hard-coded dba
name.
Listing 2 - Define loggers in a Python module
# Python logging packageimport logging# Standard instance of a logger with __name__stdlogger = logging.getLogger(__name__)# Custom instance logging with explicit namedbalogger = logging.getLogger('dba')The Python
__name__
syntax used forgetLogger
in listing 1 automatically assigns the package name as the logger name. This means if the logger is defined in a module under the application directorycoffeehouse/about/views.py
, the logger receives the namecoffeehouse.about.views
. So by relying on the__name__
syntax, loggers are automatically created based on the origin of the logging message.Don't worry about potentially having dozens or hundreds of loggers in a Django project for each module or
.py
file. As described in the past section, Python logging works with inheritance, so you can define a single handler for a parent logger (e.g.coffeehouse
) that handles all children loggers (e.g.coffeehouse.about
,coffeehouse.about.views
,coffeehouse.drinks
,coffeehouse.drinks.models
, etc).Sometimes it's convenient to define a logger with an explicit name to classify certain types of messages. In listing 2 you can see a logger named
dba
that will be used for messages related to databases issues. This way database administrators can consult their own logging stream without the need to see logging messages from other parts of the application.Once you have loggers in a module or
.py
file, you can define logging messages with one of several methods depending on the severity of a message that needs to be reported. These methods are illustrated in the following list:
<logger_name>.critical()
.- Most severe logging level. Use it to report potentially catastrophic application events (e.g. something that can halt or crash an application).<logger_name>.error()
.- Second most severe logging level. Use it to report important events (e.g. unexpected behaviors or conditions that cause end users to see an error)<logger_name>.warning()
.- Mid-level logging level. Use it to report relatively important events (e.g. unexpected behaviors or conditions that shouldn't happen, yet don't cause end users to notice the issue).<logger_name>.info()
.- Informative logging level. Use it to report informative events in an application (e.g. application milestones or user activity)<logger_name>.debug()
.- Debug logging level. Use it to report step by step logic that can be difficult to write (e.g. complex business logic or database queries)<logger_name>.log()
.- Use it to manually emit logging messages with a specific log level.<logger_name>.exception()
.- Use it to create an error level logging message, wrapped with the current exception stack.
What methods you use to log messages across your project depends entirely up to you. As far as the logging levels are concerned, just try to be consistent with the selection criteria. You can always adjust the run-time logging level to deactivate logging messages of a certain level, as described in the previous section. In addition, I would also recommend you use the most descriptive logging messages possible to maximize the benefits of logging.
Listing 3 illustrates a series of examples using several logging methods and messages:
Listing 3 - Define logging messages in a Python module
# Python logging packageimport logging# Standard instance of a logger with __name__stdlogger = logging.getLogger(__name__)# Custom instance logging with explicit namedbalogger = logging.getLogger('dba')def index(request): stdlogger.debug("Entering index method")def contactform(request): stdlogger.info("Call to contactform method") try: stdlogger.debug("Entering store_id conditional block") # Logic to handle store_id except Exception, e: stdlogger.exception(e) stdlogger.info("Starting search on DB") try: stdlogger.info("About to search db") # Loging to search db except Exception, e: stdlogger.error("Error in searchdb method") dbalogger.error("Error in searchdb method, stack %s" % (e))
If you place the loggers and logging statements like the ones in listing 3 in a Django project, you'll see that nothing happens logging wise. In fact, what you'll see in your logs are messages in the form
'No handlers could be found for logger ...<logger_name>'
. This is because by default Django doesn't know anything about your loggers, it only knows about the default loggers described in the past section. Next, lets take a look at a custom LOGGING
configuration so you can see your project's logging messages.(Note: I use django 1.11.2'No handlers could be found for logger ...<logger_name>'
issue will not occur)
Custom Django logging to send output to multiple files and modify default logging behavior
Let's start with a set of logging requirements to define our custom Django logging. The following list illustrates some modified requirements from the default logging behavior and new logging requirements.
- Modify the
console
handler to output logging message from theDEBUG
level, instead of the defaultINFO
level. - Disable all email sent to
ADMINS
via themail_admins
handler for thedjango.request
anddjango.security
loggers. - Add two custom logging formatters to enhance the logging output.
- Add a new handler as a file for logging messages from all loggers, for the
DEBUG
level and that only functions whenDEBUG=True
. - Add a new handler as a file for logging messages from all loggers except
py.warnings
, for theERROR
level and that only functions whenDEBUG=False
. - Add a new handler as a file for logging messages from the
dba
logger, for theDEBUG
level and that functions when eitherDEBUG=False
orDEBUG=True
.
Listing 4 illustrates a custom LOGGING
configuration that covers the requirements from the past list.
Listing 4 - Custom LOGGING Django configuration
LOGGING = { 'version': 1, 'disable_existing_loggers': True, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse', }, 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'formatters': { 'simple': { 'format': '[%(asctime)s] %(levelname)s %(message)s', 'datefmt': '%Y-%m-%d %H:%M:%S' }, 'verbose': { 'format': '[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d] %(message)s', 'datefmt': '%Y-%m-%d %H:%M:%S' }, }, 'handlers': { 'console': { 'level': 'DEBUG', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', 'formatter': 'simple' }, 'development_logfile': { 'level': 'DEBUG', 'filters': ['require_debug_true'], 'class': 'logging.FileHandler', 'filename': '/tmp/django_dev.log', 'formatter': 'verbose' }, 'production_logfile': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'logging.FileHandler', 'filename': '/var/log/django_production.log', 'formatter': 'simple' }, 'dba_logfile': { 'level': 'DEBUG', 'filters': ['require_debug_false','require_debug_true'], 'class': 'logging.FileHandler', 'filename': '/var/log/django_dba.log', 'formatter': 'simple' }, }, 'loggers': { 'coffeehouse': { 'handlers': ['console','development_logfile','production_logfile'], }, 'dba': { 'handlers': ['console','dba_logfile'], }, 'django': { 'handlers': ['console','development_logfile','production_logfile'], }, 'py.warnings': { 'handlers': ['console','development_logfile'], }, }}
The first important definition in listing 4 is
'disable_existing_loggers':True
which disables Django's default loggers from listing 1. If you want to keep Django's default loggers from listing 1, set this value to False
and be sure not to override any of these loggers
as we do in listing 4, as any explicit LOGGING
configuration in settings.py
takes precedence over Django defaults even when 'disable_existing_loggers':False
.Next, we have the same default filters
section as listing 1. Note that we need to redefine this section because we will use the same filters in our loggers
section. Then we have the formatters
section that will allow us to generate logging messages with a simpler and more verbose output.
By default, all Python logging messages follow the format %(levelname)s:%(name)s:%(message)s
, which means "Output the log message level, followed by the name of the logger and the log message itself". However, there is a lot more information available through Python logging that can make logging messages more comprehensive. As you can see in listing 4, we define the simple
and verbose
formatters using a special syntax and a series of fields that are different from the default. Table 1 illustrates the different Python formatter fields including their syntax and meaning.
Table 1 - Python logging formatter fields
%(name)s
Name of the logger (logging channel)%(levelno)s
Numeric logging level for the message (DEBUG, INFO,WARNING, ERROR, CRITICAL)%(levelname)s
Text logging level for the message ("DEBUG", "INFO","WARNING", "ERROR", "CRITICAL")%(pathname)s
Full pathname of the source file where the logging call was issued (if available)%(filename)s
Filename portion of pathname%(module)s
Module (name portion of filename)%(lineno)d
Source line number where the logging call was issued (if available)%(funcName)s
Function name%(created)f
Time when the log record was created (time.time() return value)%(asctime)s
Textual time when the log record was created%(msecs)d
Millisecond portion of the creation time%(relativeCreated)d
Time in milliseconds when the log record was created,relative to the time the logging module was loaded (typically at application startup time)%(thread)d
Thread ID (if available)%(threadName)s
Thread name (if available)%(process)d
Process ID (if available)%(message)s
The result of record.getMessage(), computed just as the record is emittedYou can add or remove fields to the
format
field of each formatter as you see necessary based on the fields in table 1. In addition to the format
field for each formatter, there's also the datefmt
field that allows us to define the date/time format for each logging message, which will correspond to the output of the %(asctime)s
format field. Note that the syntax for the datefmt
field follows Python's strftime() format.Next comes the four logging handlers
or locations to send logging messages. First is the console
handler which is identical to the default in listing 1, except it's set to the DEBUG
level and uses our custom simple
formatter. The remaining three handlers are all configured for file output via the 'class': 'logging.FileHandler'
statement.
The development_logfile
handler is configured to work for logging messages worse than DEBUG
(inclusive) -- which is technically all logging messages -- and only when DEBUG=True
due to the require_debug_true
filter. In addition, the development_logfile
handler is set to send output to the file /tmp/django_dev.log
and use our custom verbose
formatter.
The production_logfile
handler is configured to work for logging messages worse than ERROR
(inclusive) -- which is just ERROR
and CRITICAL
logging messages -- and only when DEBUG=False
due to the require_debug_false
filter. In addition, the handler uses the custom simpler
formatter and is set to send output to the file /var/log/django_production.log
.
The dba_logfile
is configured to work for logging messages worse than DEBUG
(inclusive) -- which is technically all logging messages -- and when DEBUG=True
or DEBUG=False
due to the require_debug_true
and require_debug_false
filters. In addition, the handler uses the custom simpler
formatter and is set to send output to the file /var/log/django_dba.log
.
Then we come to the loggers
section. The first logger coffeehouse
indicates to link all the logging messages for itself and its children (e.g. coffeehouse.about
, coffeehouse.about.views
and coffeehouse.drinks
) to the handlers console
, development_logfile
and production_logfile
. Recall that by using Python's __name__
syntax to define loggers -- see listing 2 -- the name of the loggers ends up being based on the Python package structure.
Next, you can see the custom dba
logger which links all its logging messages to the handlers console
and dba_logfile
. In this case, the handlers are limited because this is a special logger intended for database administrators, so output will only go to the console and a dedicated file with these type of messages.
Finally, we define the django
and py.warnings
loggers to re-establish some of Django's default behavior because we set 'disable_existing_loggers': True
. The django
logger links all its logging messages to the handlers console
, development_logfile
and production_logfile
, since we want logging messages associated with the django
logger and its children (e.g. django.request
, django.security
) to go to the console and two of the log files. Notice we don't declare explicit loggers for django.request
and django.security
unlike the default's in listing 1, since we will use the same handlers for the django
logger and its children. At the end, the py.warnings
logger links all its logging messages to the handlers console
and development_logfile
, as we don't want any trace of py.warnings
logging messages in production log files.
使用上述配置后还是无法输出debug 或者info 级别的信息。我查看了python 官方文档,发现logger 和 handler各自有独立的level,我试着在logger 配置里面添加了level就可以输出debug level的信息了。
'loggers': { 'coffeehouse': { 'handlers': ['console','development_logfile','production_logfile'], 'level': 'DEBUG' }, 'dba': { 'handlers': ['console','dba_logfile'], }, 'django': { 'handlers': ['console','development_logfile','production_logfile'], }, 'py.warnings': { 'handlers': ['console','development_logfile'], },}
- Django logging set up
- Set up Django, nginx and uwsgi
- Django logging
- Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 16.04和记录
- set up UBUNTU 7.10
- Tapestry 5 Set Up
- GL Set up 步骤
- GL Set up 步骤
- Set up Selenium Environment
- GL Set up 步骤
- set up my vim
- nand set up
- github set up git
- Linux set up FQDN
- Set Up Git
- 1.NativeScript Set Up
- spring set up
- Set up Git
- constone svn .a文件上传失败
- 什么是真正的实时操作系统
- 使用 Redis 实现分布式锁
- 程序员,如何从平庸走向理想?
- spark中的job和stage
- Django logging set up
- oracle中to_char()时间格式
- 实验 哈希表线性探测再散列
- 关于Java中==与equals的解析
- Github上有意思的项目推荐-web前端
- linux centos 安装jdk1.7
- 机器学习之-使用Apriori算法进行关联并分析-具体怎么实现及应用
- 内置函数与lambda匿名函数
- tair用ldb做分布式存储