Logging#
Python has a standard library for logging: logging
.
“Logging HOWTO” from docs.python.org contains two tutorials: basic and advanced.
import sys
import logging
The core components of the logging
library are:
Loggers
Handlers
Formatters
Filters
Each one defines a specific aspect of log generation.
Loggers#
For different parts of your program, you may need separate loggers
. You can create a new logger by using logging.getLogger(<logger_name>)
. Find out more details in the specific page.
The following cell demonstrates the creation of logger1
and logger2
, along with their immediate usage.
logger1 = logging.getLogger("logger1")
logger1.setLevel(logging.INFO)
print("=====logger1=====", file=sys.stderr)
logger1.debug("A DEBUG Message")
logger1.info("An INFO")
logger1.warning("A WARNING")
logger1.error("An ERROR")
logger1.critical("A message of CRITICAL severity")
logger2 = logging.getLogger("logger2")
logger2.setLevel(logging.ERROR)
print("=====logger2=====", file=sys.stderr)
logger2.debug("A DEBUG Message")
logger2.info("An INFO")
logger2.warning("A WARNING")
logger2.error("An ERROR")
logger2.critical("A message of CRITICAL severity")
=====logger1=====
A WARNING
An ERROR
A message of CRITICAL severity
=====logger2=====
An ERROR
A message of CRITICAL severity
Handlers#
Defines the direction in which logs are written. It can be files or output streams. You can add handlers to the logger using the logger.addHandler
method. Check list of the usefull handlers.
The following example demonstrates how to add a handler to a logger.
logger = logging.getLogger("temp_logger")
stream_handler = logging.StreamHandler()
logger.addHandler(stream_handler)
logger.critical("It's a error!")
# To prevent adding a handler for each
# run of this cell, we'll delete just
# added logger
del logger.handlers[0]
It's a error!
There is a specfic page describing handlers.
Formatters#
Formatters define how each line of the log is to be printed. You must set the formatter for the handler using the handler.setFormatter
method.
The following example defines formatter for given logger.
logger = logging.getLogger("some_logger")
stream_handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)
logger.error("It's error")
del logger.handlers[0]
2024-08-29 17:01:35,382 - some_logger - ERROR - It's error
Filters#
With filters, you can set specific rules for which messages should be passed to the output by handlers. Additionally, filters are a common place to customize the behavior of the logger.
Find out more:
Filter objecst section of the official
logging
documentation.Filters page on this site.
The following example demonstrates creating a logger with a filter function that returns False
if the message in the logging record contains <stop word>
.
logger = logging.getLogger("filter logger")
logger.addFilter(lambda record: '<stop word>' not in record.getMessage())
logger.critical("Just message")
logger.critical("Message with <stop word>")
Just message
Configuration#
There are some tools that allows to configure logging
module from optional key:value
like formats.
There is special page about aspects of working with it.
Here’s a simple example of how to configure an entire logging module using Python dictionaries. In this example, a logger named simpleExample
is created with a specific formatter to ensure the logs have the desired format.
logging.config.dictConfig({
"version" : 1,
"formatters" : {
"simpleFormatter" : {
"format" : "I'm created from config :) %(message)s"
}
},
"handlers" : {
"consoleHandler" : {
"class" : "logging.StreamHandler",
"formatter" : "simpleFormatter"
}
},
"loggers" : {
"simpleExample" : {
"handlers" : ["consoleHandler"]
}
}
})
logging.getLogger("simpleExample").error("{it's message}")
I'm created from config :) {it's message}
It is the preferred way to configure the logs, because anyone who is not involved with the code can participate in configuring the logs.
Root logger#
This logger is used when you run the logging methods of the logging
module itself.
Using the logging.basicConfig
function, you can define the behaviour of the logs generated by the logging
module. The following example defines the DEBUG
logging level so that you can later see any message raised by the logging
methods. By default only warning
, error
and critical
are executed.
Findout more on a special page.
In the following example, the code is saving the logs to a separate file and executing it from another interpreter. This approach is necessary because once you execute any logging method in this notebook, you cannot modify its configuration anymore.
%%writefile logging_files/root_logger.py
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("A DEBUG Message")
logging.info("An INFO")
logging.warning("A WARNING")
logging.error("An ERROR")
logging.critical("A message of CRITICAL severity")
Writing logging_files/root_logger.py
!python3 logging_files/root_logger.py
DEBUG:root:A DEBUG Message
INFO:root:An INFO
WARNING:root:A WARNING
ERROR:root:An ERROR
CRITICAL:root:A message of CRITICAL severity