Debugging
Tools and techniques for debugging the 2KRIKA application effectively.
Overview
- VS Code debugger for breakpoints
- Logging for runtime insights
- Database queries for data issues
- Network inspection for API calls
- Error tracking for production issues
VS Code Debugging
Launch Configuration
Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug NestJS",
"type": "node",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["dev"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"restart": true,
"protocol": "inspector",
"sourceMaps": true,
"envFile": "${workspaceFolder}/.env",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Debug Jest Tests",
"type": "node",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["test", "--runInBand", "--no-cache"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"protocol": "inspector",
"env": {
"NODE_ENV": "test"
}
},
{
"name": "Debug Current Test File",
"type": "node",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["test", "${file}", "--runInBand"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"protocol": "inspector"
}
]
}
Using Breakpoints
- Set breakpoint – Click left of line number
- Start debugging – Press F5 or Run → Start Debugging
- Debug controls:
- Continue (F5) – Resume execution
- Step Over (F10) – Execute current line
- Step Into (F11) – Enter function call
- Step Out (Shift+F11) – Exit current function
- Restart (Ctrl+Shift+F5) – Restart debugger
Debug Console
Access variables and execute code:
Conditional Breakpoints
Right-click breakpoint → Edit Breakpoint:
// Only break when condition is true
order.status === 'completed'
userId === 'user-123'
price.toNumber() > 10000
Logpoints
Log without stopping execution:
Logging
Application Logging
import { logger } from '@/shared/logging/file';
// Log levels
logger.info('User logged in: ' + userId);
logger.warn('Low stock for service: ' + serviceId);
logger.error('Payment failed', error);
logger.debug('Processing order: ' + JSON.stringify(order));
Query Logging
Enable in development:
View queries in logs/query.log:
Request Logging
See HTTP requests in logs/combined.log:
[2024-01-15T10:30:00.000Z] INFO: POST /api/orders - 192.168.1.1
[2024-01-15T10:30:01.123Z] INFO: POST /api/orders - 201 - 1234b
Database Debugging
PostgreSQL Console
# Connect to database
psql $SQL_DATABASE_URL
# Common queries
\dt # List tables
\d+ users # Describe table
\di # List indexes
Query Performance
-- Explain query plan
EXPLAIN ANALYZE
SELECT * FROM services
WHERE status = 'active'
ORDER BY created_at DESC
LIMIT 20;
-- Find slow queries
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;
-- Active connections
SELECT * FROM pg_stat_activity;
Transaction Debugging
// Enable transaction logging
const sequelize = new Sequelize({
logging: (sql) => {
logger.query(sql);
console.log('[Transaction]', sql);
},
});
// Manual transaction inspection
try {
const transaction = await sequelize.transaction();
// ... operations
await transaction.commit();
} catch (error) {
logger.error('Transaction failed', error);
await transaction.rollback();
throw error;
}
Network Debugging
API Testing with HTTPie
# Test endpoints
http POST localhost:3000/api/auth/login \
email=test@example.com \
password=password123
# With authentication
http GET localhost:3000/api/orders \
Authorization:"Bearer $TOKEN"
# View response headers
http -h GET localhost:3000/api/services
Postman/Insomnia
- Import OpenAPI – Use Swagger export
- Environment variables – Set base URL and tokens
- Collections – Organize by feature
- Pre-request scripts – Auto-refresh tokens
Network Tab (Browser)
- Open DevTools → Network
- Make API request
- Inspect:
- Request headers
- Request payload
- Response status
- Response body
- Timing
Error Debugging
Stack Traces
Read from bottom to top:
Error: Order not found
at OrderRepository.get (order.repository.ts:45) ← Where error was thrown
at acceptOrder (order.usecases.ts:120) ← Caller
at OrderController.accept (order.controller.ts:78) ← HTTP handler
Error Logs
Check logs/error.log:
[2024-01-15T10:32:10.789Z] ERROR: Payment failed for order: ord-456
Stack: Error: Insufficient funds
at processPayment (payment.ts:45)
at OrderWorkflow.handlePayment (workflow.ts:120)
Custom Error Classes
Add context to errors:
export class OrderNotFoundError extends Error {
constructor(public orderId: string) {
super(`Order not found: ${orderId}`);
this.name = 'OrderNotFoundError';
}
}
// Usage
try {
const order = await orderRepository.get(orderId);
} catch (error) {
if (error instanceof OrderNotFoundError) {
logger.error(`Order ${error.orderId} not found`);
}
throw error;
}
Common Issues
Port Already in Use
# Find process using port 3000
lsof -i :3000
# Kill process
kill -9 <PID>
# Or use different port
PORT=3001 pnpm dev
Database Connection Issues
# Test connection
psql $SQL_DATABASE_URL
# Check environment variable
echo $SQL_DATABASE_URL
# Verify database exists
psql -l | grep 2krika
Redis Connection Failed
# Check Redis is running
redis-cli ping
# Start Redis
redis-server
# Or use Docker
docker run -p 6379:6379 redis:alpine
Migration Errors
# Check migration status
sequelize-cli db:migrate:status
# Rollback last migration
pnpm dev:migrate:undo
# Reset database (development only!)
sequelize-cli db:drop
sequelize-cli db:create
pnpm dev:migrate
pnpm dev:seed
Memory Leaks
# Run with Node inspector
node --inspect-brk $(which nest) start
# Chrome DevTools → Memory → Take Heap Snapshot
# Compare snapshots over time
TypeScript Errors
# Clean build
rm -rf web/dist
pnpm build
# Check for type errors
tsc --noEmit
# Clear Jest cache
pnpm test --clearCache
Performance Debugging
Timing Decorator
export function logExecutionTime(
target: any,
propertyName: string,
descriptor: PropertyDescriptor
) {
const method = descriptor.value;
descriptor.value = async function (...args: any[]) {
const start = Date.now();
try {
const result = await method.apply(this, args);
const duration = Date.now() - start;
logger.info(
`${target.constructor.name}.${propertyName} took ${duration}ms`
);
return result;
} catch (error) {
const duration = Date.now() - start;
logger.error(
`${target.constructor.name}.${propertyName} failed after ${duration}ms`,
error
);
throw error;
}
};
return descriptor;
}
// Usage
export class OrderService {
@logExecutionTime
async createOrder(data: CreateOrderDTO) {
// ... implementation
}
}
Database Query Profiling
// Enable query logging with timing
const sequelize = new Sequelize({
benchmark: true,
logging: (sql, timing) => {
logger.query(`${sql} [${timing}ms]`);
},
});
Cache Hit Rate
let cacheHits = 0;
let cacheMisses = 0;
async function getCached(key: string, fetchFn: () => Promise<any>) {
const cached = await cache.get(key);
if (cached) {
cacheHits++;
logger.debug(`Cache HIT: ${key}`);
return cached;
}
cacheMisses++;
logger.debug(`Cache MISS: ${key}`);
const data = await fetchFn();
await cache.set(key, data);
return data;
}
// Report hit rate
function reportCacheStats() {
const total = cacheHits + cacheMisses;
const hitRate = total > 0 ? (cacheHits / total) * 100 : 0;
logger.info(`Cache hit rate: ${hitRate.toFixed(2)}%`);
}
Debugging Tools
NestJS DevTools
# Install
pnpm add @nestjs/devtools-integration
# Enable in app.module.ts
import { DevtoolsModule } from '@nestjs/devtools-integration';
@Module({
imports: [
DevtoolsModule.register({
http: process.env.NODE_ENV !== 'production',
}),
],
})
Sequelize Logging
const sequelize = new Sequelize({
logging: console.log, // All queries
logging: false, // Disable
logging: (sql) => logger.query(sql), // Custom logger
});
Node Inspector
# Start with inspector
node --inspect web/dist/main.js
# Chrome DevTools
chrome://inspect
# VS Code will auto-attach
Best Practices
✅ Do
- Use debugger – Breakpoints over console.log
- Log context – Include IDs and metadata
- Check error logs – Review
logs/error.logregularly - Test queries – Profile slow queries
- Use transactions – Easier to debug data issues
- Add error context – Custom error classes with details
- Monitor performance – Track execution times
- Clean up logs – Rotate and archive old logs
❌ Don't
- Don't commit console.log – Use proper logger
- Don't ignore warnings – They indicate issues
- Don't debug in production – Use proper monitoring
- Don't swallow errors – Always log and handle
- Don't skip stack traces – They show error origin
- Don't debug with data mutations – Use read-only queries
- Don't forget to remove breakpoints – Clean up before commit
Debugging Checklist
When encountering issues:
- [ ] Read error message – What does it say?
- [ ] Check stack trace – Where did it fail?
- [ ] Review recent changes – What changed?
- [ ] Check environment – Correct .env values?
- [ ] Verify database – Data as expected?
- [ ] Test in isolation – Unit test the issue
- [ ] Check logs – Any related errors?
- [ ] Review documentation – Known issue?
- [ ] Search similar issues – Stack Overflow, GitHub
- [ ] Ask for help – Team, community
Useful Commands
# Logs
tail -f logs/combined.log # Watch all logs
tail -f logs/error.log # Watch errors
grep "user-123" logs/*.log # Search logs
# Database
psql $SQL_DATABASE_URL # Connect to DB
pg_dump $SQL_DATABASE_URL > backup.sql # Backup
# Redis
redis-cli # Connect to Redis
redis-cli MONITOR # Watch all commands
# Process
ps aux | grep node # Find Node processes
lsof -i :3000 # Port usage
# Network
netstat -an | grep 3000 # Check port
curl -v localhost:3000/health # Test endpoint
Summary
Effective debugging requires:
- Proper tools – VS Code debugger, loggers
- Systematic approach – Reproduce, isolate, fix
- Good logging – Context and details
- Understanding – Read errors carefully
- Patience – Debug step by step
Master these techniques for faster problem resolution and more reliable code.