Blog |

The Ultimate Guide to Logging in Python

The Ultimate Guide to Logging in Python
Table of Contents

Logging is used to track events that happen when an application runs. Logging calls are added to application code to record or log the events and errors that occur during program execution. In Python, the logging module is used to log such events and errors.

An event can be described by a message and can optionally contain data specific to the event. Events also have a level or severity assigned by the developer.

Logging is very useful for debugging and for tracking any required information.

 

How to Use Logging in Python

The Logging Module

The Python standard library contains a logging module that provides a flexible framework for writing log messages from Python code. This module is widely used and is the starting point for most Python developers to use logging.

The logging module provides ways for applications to configure different log handlers and to route log messages to these handlers. This enables a highly flexible configuration that helps to handle many different use cases.

To write a log message, a caller requests a named logger. This logger can be used to write formatted messages using a log level (DEBUG, INFO, ERROR etc). Here's an example:

import logging
log = logging.getLogger("mylogger")
log.info("Hello World")

 

Logging Levels

The standard logging levels in Python (in increasing order of severity) and their applicability are:

  • DEBUG - Detailed information, typically of interest when diagnosing problems.
  • INFO - Confirmation of things working as expected.
  • WARNING - Indication of something unexpected or a problem in the near future e.g. 'disk space low'.
  • ERROR - A more serious problem due to which the program was unable to perform a function.
  • CRITICAL - A serious error, indicating that the program itself may not be able to continue executing.

The default log level is WARNING, which means that only events of this level and above are logged by default.

 

Configuring Logging

In general, a configuration consists of adding a Formatter and a Handler to the root logger. The Python logging module provides a number of ways to configure logging:

  • Creating loggers, handlers and formatters programmatically that call the configuration methods.
  • Creating a logging configuration file and reading it.
  • Creating a dictionary of config information and passing it to the dictConfig() function.

The official Python documentation recommends configuring via Python dictionary. To do this logging.config.dictConfig needs to be called which accepts the dictionary as an argument. Its schema is:

  • version - Should be 1 for backwards compatibility
  • disable_existing_loggers - Disables the configuration for existing loggers. This is True by default.
  • formatters — Formatter settings
  • handlers — Handler settings
  • loggers — Logger settings

It is best practice to configure this by creating a new module e.g. settings.py or conf.py. Here's an example:

import logging.config

MY_LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'default_formatter': {
            'format': '[%(levelname)s:%(asctime)s] %(message)s'
        },
    },
    'handlers': {
        'stream_handler': {
            'class': 'logging.StreamHandler',
            'formatter': 'default_formatter',
        },
    },
    'loggers': {
        'mylogger': {
            'handlers': ['stream_handler'],
            'level': 'INFO',
            'propagate': True
        }
    }
}

logging.config.dictConfig(MY_LOGGING_CONFIG)
logger = logging.getLogger('mylogger')
logger.info('info log')

 

How to Use Logging for Debugging

Besides the logging levels described earlier, exceptions can also be logged with associated traceback information. With logger.exception, traceback information can be included along with the message in case of any errors. This can be highly useful for debugging issues. Here's an example:

import logging

logger = logging.getLogger(“mylogger”)
logger.setLevel(logging.INFO)

def add(a, b):
    try:
        result = a + b
    except TypeError:
        logger.exception("TypeError occurred")
    else:
        return result

c = add(10, 'Bob')

Running the above code produces the following output:

TypeError occurred
Traceback (most recent call last):
  File "test.py", line 8, in add
    result = a + b
TypeError: unsupported operand type(s) for +: 'int' and 'str'

The output includes the message as well as the traceback info, which can be used to debug the issue.

 

Python Logging Examples

Basic Logging

Here's a very simple example of logging using the root logger with basic config:

import logging
logging.basicConfig(level=logging.INFO)
logging.info('Hello World')

Here, the basic logging configuration was set up using logging.basicConfig(). The log level was set to logging.INFO, which means that messages with a level of INFO and above will be logged. Running the above code produces the following output:

INFO:root:Hello World

The message is printed to the console, which is the default output destination. The printed message includes the level and the description of the event provided in the logging call.

 

Logging to a File

A very common use case is logging events to a file. Here's an example:

import logging
logging.basicConfig(level=logging.INFO, filename='sample.log', encoding='utf-8')
logging.info('Hello World')

Running the above code should create a log file sample.log in the current working directory (if it doesn't exist already). All subsequent log messages will go straight to this file. The file should contain the following log message after the above code is executed:

INFO:root:Hello World

 

Log Message Formatting

The log message format can be specified using the format argument of logging.basicConfig(). Here's an example:

import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')
logging.info('Hello World')

Running the above code changes the log message format to show the time, level and message and produces the following output:

2021-12-09 16:28:25,008:INFO:Hello World

 

Logging Using Handler and Formatter

Handlers and formatters are used to set up the output location and the message format for loggers. The FileHandler() class can be used to setup the output file for logs:

import logging

logger = logging.getLogger(__name__)  
logger.setLevel(logging.INFO)

file_handler = logging.FileHandler('sample.log')
formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s')
file_handler.setFormatter(formatter)

logger.addHandler(file_handler)

logger.info('Hello World')

Running the above code will create the log file sample.log if it doesn't exist already and write the following log message to the file:

2021-12-10 15:49:46,494:INFO:Hello World

 

Frequently Asked Questions

What is logging in Python?

Logging in Python allows the tracking of events during program execution. Logs are added to application code to indicate the occurrence of certain events. An event is described by a message and optional variable data specific to the event. In Python, the built-in logging module can be used to log events.

Log messages can have 5 levels - DEBUG, INGO, WARNING, ERROR and CRITICAL. They can also include traceback information for exceptions. Logs can be especially useful in case of errors to help identify their cause.

What is logging getLogger Python?

To start logging using the Python logging module, the factory function logging.getLogger(name) is typically executed. The getLogger() function accepts a single argument - the logger's name. It returns a reference to a logger instance with the specified name if provided, or root if not. Multiple calls to getLogger() with the same name will return a reference to the same logger object.

Any logger name can be provided, but the convention is to use the __name__ variable as the argument, which holds the name of the current module. The names are separated by periods(.) and are hierarchical structures. Loggers further down the list are children of loggers higher up the list. For example, given a logger foo, loggers further down such as foo.bar are descendants of foo.

 

Track, Analyze and Manage Errors With Rollbar

Managing python errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Python errors easier than ever. Sign Up Today!

Related Posts

See all posts

"Rollbar allows us to go from alerting to impact analysis and resolution in a matter of minutes. Without it we would be flying blind."

Start continuously improving your code today.

Get Started Shape