Debugging Guide¶
Tools and techniques for debugging the Odoo 15 system.
Overview¶
Effective debugging saves time and reduces frustration. This guide covers tools, techniques, and common debugging scenarios.
Quick Debugging Commands¶
# View Odoo logs in real-time
docker compose logs -f odoo
# View last 100 lines with errors
docker compose logs --tail=100 odoo | grep -i error
# Access Odoo shell
docker compose exec odoo odoo shell -d odoo_test
# Access database directly
docker compose exec db psql -U odoo -d odoo_test
# Check container status
docker compose ps
Logging for Debugging¶
Add Debug Logging¶
import logging
_logger = logging.getLogger(__name__)
def my_method(self):
_logger.debug(f"Entering my_method with self={self}")
_logger.debug(f"Context: {self.env.context}")
for record in self:
_logger.debug(f"Processing record {record.id}: {record.name}")
_logger.debug("Exiting my_method")
Enable Debug Logging¶
Or via command line:
Odoo Shell¶
Starting the Shell¶
Common Shell Commands¶
# Get current user
>>> self.env.user
res.users(1,)
# Search records
>>> orders = self.env['sale.order'].search([('state', '=', 'draft')])
>>> len(orders)
5
# Read record data
>>> order = self.env['sale.order'].browse(1)
>>> order.name
'SO001'
>>> order.partner_id.name
'Customer Name'
# Check field values
>>> order.read(['name', 'state', 'amount_total'])
[{'id': 1, 'name': 'SO001', 'state': 'draft', 'amount_total': 100.0}]
# Call methods
>>> order.action_confirm()
# Execute SQL
>>> self.env.cr.execute("SELECT id, name FROM sale_order LIMIT 5")
>>> self.env.cr.fetchall()
[(1, 'SO001'), (2, 'SO002'), ...]
# Check module
>>> self.env['ir.module.module'].search([('name', '=', 'my_module')]).state
'installed'
# Exit shell
>>> exit()
Debugging in Shell¶
# Import pdb for debugging
>>> import pdb
# Check object attributes
>>> dir(order)
['__class__', 'action_confirm', 'amount_total', ...]
# Check field definition
>>> order._fields['state']
Selection(...)
# Check model info
>>> order._name
'sale.order'
>>> order._description
'Sales Order'
# Inspect method
>>> import inspect
>>> print(inspect.getsource(order.action_confirm))
Database Debugging¶
Useful SQL Queries¶
-- Connect to database
docker compose exec db psql -U odoo -d odoo_test
-- List tables
\dt
-- Describe table
\d+ sale_order
-- Find records
SELECT id, name, state, amount_total
FROM sale_order
WHERE state = 'draft'
LIMIT 10;
-- Check for NULLs
SELECT COUNT(*) FROM sale_order WHERE partner_id IS NULL;
-- Find duplicates
SELECT email, COUNT(*)
FROM res_partner
GROUP BY email
HAVING COUNT(*) > 1;
-- Check module state
SELECT name, state, latest_version
FROM ir_module_module
WHERE name LIKE 'jdx_%';
-- Check recent changes
SELECT id, name, write_date
FROM sale_order
ORDER BY write_date DESC
LIMIT 10;
-- Exit
\q
Analyze Query Performance¶
-- Enable timing
\timing on
-- Explain query
EXPLAIN ANALYZE
SELECT * FROM sale_order
WHERE partner_id = 1;
Print Debugging¶
Basic Print Debugging¶
def my_method(self):
print("=" * 50)
print(f"DEBUG: my_method called")
print(f"DEBUG: self = {self}")
print(f"DEBUG: self.ids = {self.ids}")
print("=" * 50)
for record in self:
print(f"DEBUG: Processing {record.id}")
print(f"DEBUG: record.name = {record.name}")
print(f"DEBUG: record.state = {record.state}")
Formatted Debug Output¶
def debug_print(label, obj):
print(f"\n{'='*60}")
print(f"DEBUG: {label}")
print(f"{'='*60}")
if hasattr(obj, 'read'):
import pprint
pprint.pprint(obj.read())
else:
print(obj)
print(f"{'='*60}\n")
# Usage
debug_print("Order Data", order)
debug_print("Context", self.env.context)
Breakpoint Debugging¶
Using pdb¶
def my_method(self):
import pdb; pdb.set_trace() # Breakpoint
for record in self:
# Code will stop here
result = self._process(record)
pdb Commands¶
| Command | Description |
|---|---|
n |
Next line |
s |
Step into function |
c |
Continue execution |
p var |
Print variable |
pp var |
Pretty print variable |
l |
List source code |
w |
Show stack trace |
q |
Quit debugger |
h |
Help |
Using breakpoint() (Python 3.7+)¶
Remote Debugging (VS Code)¶
Setup¶
-
Install
debugpyin container: -
Add debug entrypoint:
-
VS Code launch.json:
Common Debugging Scenarios¶
Module Won't Load¶
# Check for syntax errors
docker compose exec odoo python -c "import sys; sys.path.insert(0, '/mnt/extra-addons/odoo'); import my_module"
# Check manifest
docker compose exec odoo python -c "
import ast
with open('/mnt/extra-addons/odoo/my_module/__manifest__.py') as f:
print(ast.literal_eval(f.read()))
"
# Check Odoo logs
docker compose logs odoo | grep -i "my_module"
Record Not Found¶
# In Odoo shell
>>> record = self.env['my.model'].browse(123)
>>> record.exists()
my.model() # Empty = doesn't exist
# Check in database
>>> self.env.cr.execute("SELECT * FROM my_model WHERE id = 123")
>>> self.env.cr.fetchone()
None # Doesn't exist
Field Value Not Updating¶
# Check if field is computed
>>> field = self.env['my.model']._fields['my_field']
>>> field.compute
'_compute_my_field' # It's computed
# Force recompute
>>> records = self.env['my.model'].search([])
>>> records._compute_my_field()
# Check if stored
>>> field.store
True
Method Not Being Called¶
# Add logging to verify
def my_method(self):
_logger.info(f"my_method called with {self.ids}")
import traceback
_logger.info(f"Call stack:\n{traceback.format_stack()}")
Access Rights Issues¶
# In shell, check as different user
>>> user = self.env['res.users'].browse(2)
>>> self.env = self.env(user=user)
>>> self.env['my.model'].search([]) # Will fail if no access
# Check access rights
>>> self.env['ir.model.access'].search([
... ('model_id.model', '=', 'my.model'),
... ('group_id', 'in', user.groups_id.ids)
... ])
Performance Debugging¶
Profile Code¶
import cProfile
import pstats
def my_method(self):
profiler = cProfile.Profile()
profiler.enable()
# Code to profile
result = self._do_heavy_work()
profiler.disable()
stats = pstats.Stats(profiler)
stats.sort_stats('cumulative')
stats.print_stats(20) # Top 20
return result
Log SQL Queries¶
# Enable SQL logging
import logging
logging.getLogger('odoo.sql_db').setLevel(logging.DEBUG)
# Or in odoo.conf
log_handler = odoo.sql_db:DEBUG
Count Queries¶
def my_method(self):
# Count queries before
query_count_before = self.env.cr.sql_log_count
# Do work
self._do_work()
# Count queries after
query_count = self.env.cr.sql_log_count - query_count_before
_logger.info(f"Method executed {query_count} queries")
Network Debugging¶
Test API Endpoints¶
# Test from inside container
docker compose exec odoo curl http://localhost:8069/web/health
# Test from host
curl http://localhost:8069/web/health
curl http://localhost:5000/health
# Test with authentication
curl -X POST http://localhost:8069/jsonrpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"call","params":{},"id":1}'
Check Container Networking¶
# Check network
docker network inspect odoo15-jdx-production_default
# Test connectivity between containers
docker compose exec pwa ping odoo
docker compose exec nginx ping odoo
Debugging Checklist¶
Before Debugging¶
- Can reproduce the issue?
- Checked the logs?
- Recent code changes?
- Works in other environment?
During Debugging¶
- Add logging at key points
- Check input values
- Verify database state
- Test in isolation
After Fixing¶
- Remove debug code
- Add test to prevent regression
- Document the fix
- Update error handling if needed
Quick Reference¶
Log Commands¶
docker compose logs odoo # All logs
docker compose logs -f odoo # Follow
docker compose logs --tail=100 odoo # Last 100