The Ultimate Python Debugging Tool: Using PyCharm Breakpoints and Log Analysis to Quickly Identify Bug Sources

“It worked fine during testing, but it throws an error once it’s live!”

“This exception message is so confusing, where did it go wrong?”

“I fixed one bug, but three new bugs popped up…”

Does this experience sound familiar? Don’t worry, today I’m going to help you master the ultimate weapon for Python debugging:

Using PyCharm breakpoints along with log analysis, you can quickly pinpoint the issues in your code like a seasoned detective!

First: Master the art of breakpoint debugging—make the code execution process “transparent”.

Breakpoint debugging is like giving your code a “slow-motion replay” feature, allowing you to observe the program’s execution step by step.

Common pain points of traditional debugging:

1. Blindly adding print statements, which is inefficient.

2. Unable to observe the internal state of the program during execution.

3. Difficult to reproduce complex error scenarios.

The complete process of breakpoint debugging:

python

# Example: A function for calculating e-commerce inventory value with potential issues

def calculate_inventory_value(products):

total_value = 0

# Set a breakpoint here – click the area to the right of the line number

for product in products:

price = product.get(‘price’, 0)

quantity = product.get(‘stock’, 0)

discount = product.get(‘discount’, 1.0)

# Calculate the value of a single product

product_value = price * quantity * discount

total_value += product_value

# Observe variable changes – check in the Debug window

print(f”Product: {product.get(‘name’)}, Value: {product_value}”)

return total_value

# Test data

sample_products = [

{‘name’: ‘Wireless Headphones’, ‘price’: 299, ‘stock’: 50, ‘discount’: 0.9},

{‘name’: ‘Power Bank’, ‘price’: 159, ‘stock’: 30},

{‘name’: ‘Phone Case’, ‘price’: 49, ‘stock’: 100, ‘discount’: 0.8}

]

# Right-click in PyCharm and select “Debug” to run

result = calculate_inventory_value(sample_products)

print(f”Total inventory value: {result}”)

The core techniques of breakpoint debugging:

Set breakpoints at critical lines of code, and the program will automatically pause when it reaches this point.

Use Step Over to execute line by line and observe the program flow.

Utilize Step Into to dive into function internals and see detailed execution processes.

Monitor variable value changes in real-time through the Variables window.

Isn’t it amazing? It’s like having the superpower of “time pause”, allowing you to check the code state at any moment!

Second: Make good use of log analysis—install a “black box” for your program.

If breakpoint debugging is a “microscope”, then log analysis is the program’s “dashcam”, recording the complete execution trajectory of the code.

The three important levels of log recording:

DEBUG level: Records detailed technical details.

INFO level: Records normal business processes.

ERROR level: Records errors and exceptions.

Implementing a complete solution for intelligent log recording:

python

import logging

import os

from datetime import datetime

def setup_logging():

# Create logs directory

if not os.path.exists(‘logs’):

os.makedirs(‘logs’)

# Configure log format

log_format = ‘%(asctime)s – %(name)s – %(levelname)s – %(message)s’

# Set log level and output file

logging.basicConfig(level=logging.DEBUG, format=log_format, handlers=[

logging.FileHandler(f’logs/debug_{datetime.now().strftime(“%Y%m%d”)}.log’),

logging.StreamHandler() # Also output to console

])

def process_user_order(user_data, order_items):

logger = logging.getLogger(‘Order Processing’)

try:

logger.info(f”Starting to process order for user {user_data[‘user_id’]}.”)

total_amount = 0

for item in order_items:

logger.debug(f”Processing item: {item[‘name’]}, Price: {item[‘price’]}”)

if item[‘price’] <= 0:

logger.warning(f”Item {item[‘name’]} has an abnormal price: {item[‘price’]}”)

total_amount += item[‘price’] * item[‘quantity’]

logger.info(f”Total amount calculated: {total_amount}”)

return total_amount

except Exception as e:

logger.error(f”Order processing failed: {str(e)}”, exc_info=True)

return None

# Initialize logging system

setup_logging()

# Test log functionality

test_user = {‘user_id’: ‘U1001’, ‘name’: ‘Zhang San’}

test_order = [{‘name’: ‘Python Programming Book’, ‘price’: 89, ‘quantity’: 2}, {‘name’: ‘Wireless Mouse’, ‘price’: 159, ‘quantity’: 1}]

result = process_user_order(test_user, test_order)

The logging system is like the “autobiography” of the program, detailing every important moment, making problem identification more reliable!

Third: Combination usage techniques—building a complete debugging system.

Using breakpoint debugging or log analysis alone is already very useful, but the combination of both can produce an effect greater than the sum of its parts.

Practical plan for building a debugging system:

python

import logging

class DebugHelper:

def __init__(self, module_name):

self.logger = logging.getLogger(module_name)

def debug_function(self, func):

“””Decorator: Adds debugging support to a function”””

def wrapper(*args, **kwargs):

self.logger.info(f”Function {func.__name__} started executing.”)

self.logger.debug(f”Parameters: args={args}, kwargs={kwargs}”)

try:

result = func(*args, **kwargs)

self.logger.info(f”Function {func.__name__} executed successfully.”)

return result

except Exception as e:

self.logger.error(f”Function {func.__name__} execution failed: {str(e)}”)

raise

return wrapper

# Usage example

debug_tool = DebugHelper(‘Inventory Management’)

@debug_tool.debug_function

def update_product_stock(product_id, new_stock):

if new_stock < 0:

raise ValueError(“Stock quantity cannot be negative”)

print(f”Updating product {product_id} stock to {new_stock}”)

return True

# Test various scenarios

try:

update_product_stock(‘P1001’, 50) # Normal case

update_product_stock(‘P1002’, -5) # Exception case

except Exception as e:

print(f”Caught exception: {e}”)

The advantages of this debugging system:

Logs provide a complete execution history.

Breakpoint debugging allows for in-depth analysis of specific problem scenarios.

The decorator pattern separates debugging code from business logic.

Conditional breakpoints only trigger under specific conditions, improving debugging efficiency.

Mastering these debugging techniques will transform you from “blind guessing” to “precise localization”:

Breakpoint debugging lets you see every detail of code execution.

Log analysis provides a complete timeline of when issues occur.

Combining both makes the debugging process comprehensive and in-depth.

Remember these three debugging principles:

Good programmers don’t avoid bugs; they fix them quickly.

More debugging tools aren’t necessarily better; the more refined, the better.

Problem-solving isn’t about luck; it’s about a systematic approach.

Start practicing these techniques now! Open your PyCharm and try using breakpoint debugging and log analysis in your next project. When you first quickly locate and resolve a complex issue through debugging, you’ll truly experience the sense of achievement and control in programming.

Debugging is not the enemy of programming; it is the best teacher for understanding code. From today on, let debugging become your powerful assistant in programming, turning every bug into an opportunity for progress!

Click on the card above to follow the blogger “Poetry and Backpack”

Leave a Comment