Python provides a built-in library called logging to make it easy to add logging to any module or application in a unified way. Let's see how can we use it.
Simple logging
The most simple way to get started with logging is to import the logging
module and then call
the various logging methods on it. There are 5 primary levels of logging. Each one has a corresponding numeric value and a method to log on that level.
In addition we can call the log
method passing to it the level as provided by the appropriate name in upper case (logging.WARNING
in our example) or we can even pass the numerical value by ourself, though that makes of a much less readable code.
examples/python/simple_logging.py
import logging
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.error("error")
logging.critical("critical")
logging.log(logging.WARNING, "another warning")
logging.log(40, "another error")
If we run the above script we get the following output:
WARNING:root:warning
ERROR:root:error
CRITICAL:root:critical
WARNING:root:another warning
ERROR:root:another error
- By default the
logging
module only displays the levels WARNING and up. - By default it prints then to the Standard Error channel (STDERR).
- The format is LEVEL followed by the name of the default logger (root), followed by the message
Basic Configuration: Set the log level for logging in Python
We can easily adjust the level of logging to be INFO and above by calling the basicConfig
method:
examples/python/simple_logging_set_level.py
import logging
logging.basicConfig(level = logging.INFO)
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.error("error")
logging.critical("critical")
The output will be:
INFO:root:info
WARNING:root:warning
ERROR:root:error
CRITICAL:root:critical
Send log to a file
We can also configure the logging module to save the log messages in a file, instead of the STDERR
by adding the filename
parameter to the basicConfig
method call:
logging.basicConfig(level = logging.INFO, filename = "my.log")
This will create the log file if it does not exists and append the content of the file, if it already existed.
This means the file can grow in size quite fast so a better idea might be to use some kind of a log-file rotation tool or to create log files for limited time periods. E.g. One file per day. For this we can use the time.strftime method:
examples/python/simple_logging_to_file.py
import logging
import time
logging.basicConfig(level = logging.INFO, filename = time.strftime("my-%Y-%m-%d.log"))
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.error("error")
logging.critical("critical")
This will use files in the following format: my-2018-06-12.log
. Please don't use British or American date formats here.
Those are really confusing and break the sorting order.
Alternatively you could change it by adding filemode = 'w'
that will change the mode of operation from "append" to "write"
and will overwrite the file every time we run our application. This usually is not very useful as this mean we lose all the old logs.
Formatting the log message, including date
We can replace the default log message format using the format
parameter and some keywords representing the various fields
supplied by the logging module:
examples/python/simple_logging_format.py
import logging
logging.basicConfig( format = '%(asctime)s %(levelname)-10s %(processName)s %(name)s %(message)s')
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.error("error")
logging.critical("critical")
The output will look like this:
2018-06-12 08:46:22,942 WARNING MainProcess root warning
2018-06-12 08:46:22,942 ERROR MainProcess root error
2018-06-12 08:46:22,942 CRITICAL MainProcess root critical
Change the date format in the log
Though I don't really recommend to change the date format, you can do that by passing the datefmt
parameter
with a string using the strftime tags.
examples/python/simple_logging_format_date.py
import logging
logging.basicConfig( format = '%(asctime)s %(levelname)-10s %(processName)s %(name)s %(message)s', datefmt = "%Y-%m-%d-%H-%M-%S")
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.error("error")
logging.critical("critical")
The output will then change to:
2018-06-12-08-51-30 WARNING MainProcess root warning
2018-06-12-08-51-30 ERROR MainProcess root error
2018-06-12-08-51-30 CRITICAL MainProcess root critical
Comments
logging.basicConfig(level = logging.INFO, filename = "my.log")
This statement won't create the log file automatically for you.
Have you tried https://simplelogging.readthedocs.io/en/latest/readme.html ? You don't have to remember the boilerplate anylonger.
Log to file doesnt work with this code