Log Levels Explained and Exemplified

This is an appendix article, written following the article Log Your Flow. The purpose of this article is to summarize and exemplify the different log levels that we use in our code.
The levels explained below are ordered by severity level – ascending order. When we read logs, we can expose the desired severity level. Exposing a specific severity level – exposes to us, the readers, the higher levels as well. So if we choose "info" level, for example, warning & error & critical will be visible to us as well. And if we choose "critical" level, this will be the only log level that we see logging-reading-system.

The explanations below are followed by examples. All examples are of a car-loan application system. The system checks the customer’s eligibility for a car loan, and if eligible – the system calculates the loan amount the customer is eligible for.
Debug
Used to provide diagnosis information for developers, IT, Tech-Support, etc. Answers the questions "why did this issue happen?", "why was this scenario triggered?"
logger.debug(f'Cannot offer the customer {customer_id} car loan - the customer is underage')
Info
This level provides information in a "happy flow", about legitimate events that happened in the code.
In some companies, it is also the default level that is visible when Debugging in production and therefore is considered the most "verbose" log level for prod-debugging purposes.
At this level, we will provide info regarding relevant changes we want to be informed about.
logger.info(f'Customer {customer_id} - car loan application is approved. Loan amount is {loan_amount}')
Warning
This is relevant when we might have an error occurring in the system. The error may re-occur or be independently resolved, but key features / processes of the system are working properly.
logger.info(f'Customer {customer_id} - car loan application is approved. Loan amount is {loan_amount}')
logger.warning(f'Customer {customer_id} - approval notification failed. Retrying to notify the customer')
Error
An error that interferes with the proper operation, but not to the application itself. These errors will require a developer / IT / customer to take additional steps to resolve the issue, but these steps do not include a major intervention such as restarting the app.
logger.error(f'Customer {customer_id} - eligibility for car loan cannot be processed. Bank statements provided by the customer are empty')
Critical
A critical error that requires the application to be shut down / restarted in order to prevent further damage such as data loss or additional data loss.
logger.critical(f'Connection to DB is lost at {datetime.datetime.now()}')
Exception
Reading stack trace of exceptions is also a part of our debugging process when we skim over Logs.
While the "error" log level exists and is used in many cases, we need to take into account that, unless otherwise defined, the usage of error logs will not print the location of our error. But an exception’s stack trace will.
This can be done as follows:
def dividing_by_zero(a):
try:
a / 0
except ZeroDivisionError:
logger.exception('my exception message')
>>> dividing_by_zero(2)
ERROR:__main__:my exception message
Traceback (most recent call last):
File "/Users/my_user/my_repo/my_module/my_file.py", line 12, in dividing_by_zero
1 / 0
ZeroDivisionError: division by zero
FOOTNOTE
This article was written from a "Pythonic point of view". When writing your logs in other programming languages, you may realize a few differences. For example – "critical" may be replaced with "fatal", or additional log levels can be in use, such as "trace".
Covering all the differences between logs in Python vs. logs in other languages is out of scope for this article, but I will briefly explain about "trace" level:
"Trace" is used in order to indicate "where we are" in the code, and appears in a lower severity level than "info". For example – we got into an important "if" or "else" statement in the code, entered a specific function, etc.
logger.trace(f'Customer {customer_id} - starting to calculate average bank balance in the past {MONTHS_TO_CHECK} months based on bank statements')