Even if you write clean, efficient, readable code and have good coverage of your code with unit test cases, it is impossible to write once and run it all the time perfectly. In most cases, bugs are inevitable, and debugging is part of the daily life of a developer. Therefore, learning debugging tricks will improve your and your code’s performance and efficiency. This post introduces you to some tricks and tools for easier debugging in Python.
Strategies
The first and foremost step of effective debugging is identifying the actual error. Once we get the error details, we need to find the error location, analyze the condition of the error and the underlying cause of the issue and resolve it. You need to have the right strategy along with the right tools.
There are a couple of strategies for debugging. One is forward analysis, and the other is backward analysis.
The forward analysis method involves re-running the code in debugger mode, setting up the breakpoint in the suspicious line, and debugging it. To do forward analysis, you can use pdb and IDE to debug efficiently.
The backward analysis method involves tracing the problem using the logs collected from the production environment when the error occurred. For doing backward analysis, tools like print functions, logger, snapshots, etc., work.
The combination of backward and forward analysis can be implemented for real-time debugging using tools like Lightrun Cloud, which we will discuss later in this article.
Using such tools, developers can perform real-time debugging in any type of application—monolith and legacy applications, microservices, and distributed systems. Integrating with the APM and other DevOps tools gives developers access to snapshot, log, and performance metrics to identify the bug and resolve the issue efficiently.
Forward Analysis with Python Debugger (pdb)
If you enable the program to run in the single-step mode, you can check the status of the running code anytime. pdb is Python’s built-in debugger tool. There are some other tools, like web-pdb, but in most cases, pdb is useful enough.
To run the program in pdb, run the following command:
python -m pdb addition.py
The program will start running the first step. If you want to skip and run full code, press 1. To execute the next line, press n. This will help you understand the variable values and the flow of execution.
If your code is large and you want to set breakpoints, use the set_trace method:
Forward Analysis with IDE Debugger
Most IDEs have a lot of functionalities, like set breakpoint, step over, step into, continue, etc. These commands help developers debug efficiently. Some of the current good IDE available for Python are:
PyCharm: The PyCharm IDE from JetBrains has an integrated debugger and test runner along with a huge collection of tools out of the box.
Visual Studio Code: Visual Studio Code has Python support with the Microsoft Python extension.
If you are using Windows 10 or 11 and building applications for Linux Systems, WSL is a great way to do development and testing. Visual Studio coupled with the Remote WSL extension and Python extension gives developers access to editing and remote debugging as it runs in WSL.
In a few cases, it is not possible to reproduce a similar scenario. In such cases, backward analysis helps the developer identify and resolve the issue.
Backward Analysis with Print/Assert Function
The simplest yet powerful method of debugging is printing the variables and event messages to the console and checking whether the value printed is expected or something went wrong in the code execution.
To overcome the problem in print statements, developers can use assert statements. Python’s built-in assert method can raise an AssertionError if its statement condition is not met.
Python gives you the flexibility to enable or disable when using assert. You can use the -0 argument while running the code to close all the assert statements in the program. After that, all the assert methods will not work.
Still, having a lot of assert statements makes the code not readable and a bit confusing.
Backward Analysis with Logger
Replacing all the print statements with the logger is the most professional and powerful way to debug log statements. It is a heavy weapon for developers because it gives them more flexibility to enable and disable. Moreover, there are log levels that you can set to enable certain logs.
One of the easiest ways to debug with the log statement is by adding the debug statement in all the methods. So, when any method is executed, the method will log a debug statement with the values of the arguments. Instead of writing the log statement in all the methods, the developer can use the decorator function, which will internally log the values of the arguments. Use the code snippet below to create a decorator function and add @enable_args_debugger before all the methods where you want to print the arguments.
Lightrun Cloud
Whether the application is on cloud or on-premise, running on an application server or serverless, or is containerized, Lightrun Cloud is a free tool that helps developers easily identify issues and resolve them quickly. It reduces delivery time and adds flexibility to add logs or snapshots in real-time without changing the code.
Real-Time Debugging with Lightrun Logs
It is a tedious process to add logs or an assert statement after the code is shipped. Instead of invoking the CI/CD pipeline for a couple of line changes, you can use Lightrun Logs to add logs. It allows you to add as many logs as you want in the run-time on the production system. It can be integrated with the leading IDEs. With this tool, developers can freely focus on the core business logic under the bells and whistles.
Real-Time Debugging with Lightrun Snapshots
In many cases, developers have a hard time understanding the flow of execution. If the developer has the stack trace and the variables, it is easy for them to understand if there is missing logic or if the conditional execution is not working as expected. Lightrun Snapshots are virtual breakpoints that extract all the data without breaking the system.
With Lightrun, you can have conditional snapshots, integrate with the IDE you are using, and add as many snapshots as you want without breaking the system.
Real-Time Debugging with Lightrun Performance Metrics
Bugs are not only missing/wrong logic. They can be bottlenecks and long queries too. These performance-related bugs can be addressed using Lightrun. You can add performance metric monitoring along with logs examples, count the number of times the particular code is executed, measure the time between two function executions, and collect system stats, like latency and throughput counters.
Developers and DevOps engineers use multiple tools for each debugging strategy, like remote debugging, log shipping, application performance monitoring, and memory snapshot. However, Lightrun Cloud is the one place to satisfy all your developer needs for debugging, including logging, metrics and APM, snapshot, and remote debugging. It also integrates with various DevOps tools, which enables smooth implementation of its advantages.
Also published on Medium.