How to Log a Python Error with Debug Information?

Generally, logging is an extremely valuable tool in a software developer’s toolbox. Logging helps to assist you with the flow of a program and find situations that you probably would not have considered while coding. By logging useful data and information, you can troubleshoot the errors effectively as well as utilize the information to examine the performance of the application to anticipate scaling the program. 

Python provides us with a logging framework (standard library) to rapidly add logging to our application. One can import the logging module and use it in their program. The logging module has various functions to get detailed information like the line number, stack traces to the line where the error occurred. In this tutorial, let us learn about different levels of logging and different ways to log a Python Error with debug information.

A Quick Introduction to The Logging Module

The logging module is used in Python to track the event that happens while our programming software runs. You can add logging calls to your code to demonstrate what occasions have occurred. The logging module considers both- demonstrative logging that records occasions identified with an application’s activity as well as, review logging which records the occasions of a user’s transactions for examination. It is particularly used to record occasions to a document or file. 

To add the logging module in your Python program using the following command:

Import logging

🎚️Different Levels of Logging

Based on the severity, there are FIVE different logging levels :

  1. DEBUG – used to log the Details.
  2. INFO – used to log informational messages when something runs as expected.
  3. WARNING – used to log warnings when there is a problem, but the code can run to completion.
  4. ERROR – used to log an error indicating a problem to perform an action.
  5. CRITICAL– used to log a serious error when the code cannot run to completion.

By default, the module logs only the Warning, Error, and Critical levels. Meaning, when the program runs as expected, nothing is logged unless you change the default settings. But, the module logs a warning or an error, or a critical event it encounters.

Overview of Stack Trace in Python

The Python stack trace stores a significant piece of data that you can use to debug your code. It contains all information about the call stack and shows where the code went wrong. Towards the end of a stack trace, you can generally track down the specific exception type and a detailed message of where exactly the error occurred.

Generally, a stack trace report contains all the function calls made in your code just before the error occurred. At the point when your program raises an exception, it will print the stack trace. The following is an example of a basic Python script that will raise an exception:

Example:

def foo(n):
  
    print('The number is ', y)
foo(10)

Output:

Traceback (most recent call last):
  File "main.py", line 3, in <module> foo
    foo(n)
  File "main.py", line 2, in foo
    print('The number is ', y)
NameError: name 'x' is not defined

The stack trace report has a lot of information regarding what went wrong in the program. It first mentions the type of error that happened: NameError. This explains that we’ve referred to a variable that doesn’t exist. It also displays the variable we attempted to reference. Here, y is not defined. The debug information is usually the stack trace report. 

Now that you know what attack trace and logging are, let’s dive into the various methods to log a Python error with debug information:

💡Method 1: Using logging.{level}()

Use this method to log the information at different log levels. 

⦿ If you want to display only the custom error message, the syntax is :

logging.{level}(msg)

where,

level


can be debug, info, warning, or critical.
msgis any custom message.

Example: In this example, let us use logging.error() to log an error with a custom message.

import logging
import math

def find_sqrt(x):              #function to find square root of a number
 try:
 return(math.sqrt(x))          #returns squareroot of a number
 except ValueError:            
       logging.error("Check the value.s Negative numbers cannot be passed")

find_sqrt(-2)

Output:

ERROR:root:Check the value. Negative numbers cannot be passed

⦿ If you want to log the Custom error message along with stack trace, the syntax is :

logging.{level}(msg,stack_info=True)
level

can be debug, info, warning, error, critical.
msgis any custom message.

Example: In the following example, let us use logging.error() with the parameter stack_info to log an error with a custom message and stack trace pointing to the error.

import logging
import math

def find_sqrt(x):              #function to find square root of a number
   try:
       return(math.sqrt(x))    #returns squareroot of a number
   except ValueError:          #Error- when negative number is passed
       logging.error("Check the value. Negative numbers cannot be passed",stack_info=True)

find_sqrt(-2)

Output:

ERROR:root:Check the value. Negative numbers cannot be passed

Stack (most recent call last):

 File "C:\Users\admin\Desktop\Finxter\main.py", line 15, in <module>
   find_sqrt(-2)

 File "C:\Users\admin\Desktop\Finxter\main.py", line 13, in find_sqrt
   logging.error("Check the value. Negative numbers cannot be passed",stack_info=True)

💡Method 2 : Using logging.exception()

What is an exception in Python?
In Python, an exception is an object that addresses an error. At the point when the script raises an exception, it should either deal with the exception, else the program stops running and terminates.

You can use the logging.exception() when you want to log the exception messages and get details of the line number. Make sure to use it only within an except block.

Syntax: logging.exception(msg)
NOTE: exception() logs at the ERROR level and with exc_info. Meaning, it is the same as executing, logging.error(msg,exc_info=3)

To show detailed debug information and data, you first have to import the logging library in Python and then use the logging.exception() method. This method usually logs the message with a level “Error” on the logger. The exception information also gets added to the logging message. The logging.exception() method must be called from an exception handler.

Example:

# Importing the logging module
import logging
def foo(n):
    # The try block
    try:
        res = n / 0
        print("Result = ", res)
   
    # The except block
    except :
        # logging.exception() method inside the except block 
        logging.exception("The debugged error message is -")
foo(10)

Output:

ERROR:root: The debugged error message is -
Traceback (most recent call last):
  File "main.py", line 4, in foo
    res = n / 0
ZeroDivisionError: division by zero

In the above example, we have got detailed debug information regarding the error:

  • It displays the exact function (foo) where the error occurred. 
  • It also displays the line number (line 4) where the error occurred. 
  • It also displays the cause of the error. (ZeroDivisionError: division by zero.)

⦿ Using logging.exception() with exc_info:

By default, the logging.exception() method utilizes the log level of ERROR. Although, you can utilize the customary logging techniques like logging.debug(), logging.info(), logging.warn(), and so forth. For this, you have to pass the exc_info parameter. 

Example:

# Importing the logging module
import logging
def foo(n):
    # The try block
    try:
        res = n / 0
        print("Result = ", res)
   
    # The except block
    except  Exception as e:
        # logging.exception() method inside the except block 
        logging.exception("The debugged error message is -", exc_info = e)
foo(10)

Output:

ERROR:root: The debugged error message is -
Traceback (most recent call last):
  File "main.py", line 4, in foo
    res = n / 0
ZeroDivisionError: division by zero

Note:

  • The exc_info holds the current exception information only if an exception occurs in the program else, it will hold None.
  • The exc_info parameter also accepts instances. You can even set the parameter to be True.

Look at the following example:

# Importing the logging module
import logging
def foo(n):
    # The try block
    try:
        res = n / 0
        print("Result = ", res)
   
    # The except block
    except 
Exception:
        # The logging.exception() method inside the except block 
        logging.exception("The debugged error message is -", exc_info = True)
foo(10)

Output:

ERROR:root: The debugged error message is -
Traceback (most recent call last):
  File "main.py", line 4, in foo
    res = n / 0
ZeroDivisionError: division by zero

Setting the exc_info to True causes the logging module to include the full stack trace exactly like logging.exception() does.

💡Method 3: Using traceback Module

We recommend using the logging module to log. But, at times, when you cannot use the logging module, use the traceback module with some tweaks as shown below.

import traceback,sys

try :
	#do something
except:
	exc_type, exc_value, exc_traceback = sys.exc_info()  
      print(" ".join(traceback.format_exception(exc_type, exc_value, exc_traceback)))

Example – Let us import the traceback module, extract values of the exception that is being handled. Format the values into a list and join the list to display the error message as shown below.

import traceback,sys
import math

def find_sqrt(x):            #function to find square root of a number
 try:
 return(math.sqrt(x))        #returns squareroot of a number
 except ValueError:         
       # extract the information from tuple about the exception
       exc_type, exc_value, exc_traceback = sys.exc_info()  
       print(" ".join(traceback.format_exception(exc_type, exc_value, exc_traceback)))
find_sqrt(-2)

Output:

Traceback (most recent call last):

  File "C:\Users\admin\Desktop\Finxter\main.py", line 11, in find_sqrt

   return(math.sqrt(x))        #returns squareroot of a number

ValueError: math domain error

Conclusion

We hope you have found this article helpful. Please stay tuned and subscribe for more solutions and interesting discussions in the future. Till then Happy Pythoning!

RECOMMENDED READS: Errors in Python

Authors:– 
👩‍🎓 ANUSHA PAI
👩‍🎓 RASHI AGARWAL
Co-author: SHUBHAM SAYON


To become a PyCharm master, check out our full course on the Finxter Computer Science Academy available for free for all Finxter Premium Members: