//TODO:
[ ] warnings.warn, for example, from elasticsearch package
https://docs.python.org/3/howto/logging.html#when-to-use-logging
Default handler for child logger: When no handler set to child
logger and you call logger.info() and so on, there is a last resort:
logging.lastResort
:
1 | import logging |
From experience, for complex application logging:
- inherit logging.Logger class to creat customized logger class
- create log output folder if does not exist
- update default logging dict config and applied
- set custom logger class
- get logger and return to module
My logging framework for complex application, for simple application, just use code configuration to set up module’s logger layout.
Introduction
Official document, read through carefully.
Default output
: by default, no destination is set for any logging messages.
They will check to see if no destination is set; and if one is not set, they
will set a destination of the console (sys.stderr
).
First, know when to use logging.
Multiple calls to getLogger()
with the same name will return a reference to
the same logger object (singleton).
Loggers have a concept of effective level
. If a level is not explicitly set on
a logger, the level of its parent is used instead as its effective level. If the
parent has no explicit level set, its parent is examined, and so on. When
deciding whether to process an event, the effective level of the logger is used
to determine
whether the event is passed to the logger’s handlers.
Child loggers propagate messages up to the handlers
associated with their
ancestor loggers. Because of this, it is unnecessary to define and configure
handlers for all the loggers an application uses. It is sufficient to configure
handlers for a top-level logger and create child loggers as needed. (You can,
however, turn off propagation by setting the propagate
attribute of a logger
to False
.) 注意,propagate 不会受到 parent logger level 的影响, 都会收到下级的信息.
Thread safety: It achieves this though using threading locks; there is one lock to serialize access to the module’s shared data, and each handler also creates a lock to serialize access to its underlying I/O.
Cookbook highlights:
- logger name can be chained, logging.getLogger: apple, apple.pear, apple.pear.peach, child log will pass to parent.
- support threads.
- one logger can have multiple handler and formatter: Sometimes it will be beneficial for an application to log all messages of all severities to a text file while simultaneously logging errors or above to the console. The root logger level should <= handler level, otherwise handler will not receive messages.
- console message may no need to contain timestamp, but log file needs.
- To dynamic change log configuration, you can use signal handler or using log config server, it is listening on port to receive new configuration.
- pass log level to cli application
Logging level: DEBUG
, INFO
, WARNING
, ERROR
, CRITIAL
, in increasing
order of severity. 设置这个的好处是可以根据level输出对应的logging信息,在设定level之下的
logging不会被记录, 比如当前level 设定为INFO, 则logging.debug()不会被输出。
The default level is WARNING
, which means that only events of this level and
above will be tracked, unless the logging package is configured to do otherwise.
Basic Usage
See Basic Logging Tutorial. This is not good for practical use as set basicConfig will impact other imported modules, but for simple usage it is fine.
logging.basicConfig only initializes root logger.
1 | import logging |
For json format log, there is a open source module: https://github.com/madzak/python-json-logger
NOTE: The desired
logging.basicConfig()
should come at very first and it only take effect once.
Advanced Usage
More advanced usage please see: https://docs.python.org/3.8/howto/logging.html#advanced-logging-tutorial
Configuring separated logger for different modules.
1 | import logging |
Log Rotating
1 | # size based |
Log Config File
For complex logging configuration, we can write a config file, the format can be ini-style or dict-style. This way we don’t need to hard code or change the configuration in the code.
1 | import logging |
Signal Trap
In production we can use signals to change logging level dynamically, for example:
1 | import signal |
It depends on how you initializes the logger, you can also update the handler’s logging level:
1 | import logging |
For docker container please run signal script as init process or use tini
to
forward signal.