Stop Putting dd() Everywhere Debug the Database From the Source Instead
Source: Dev.to
The Problem with Scattering dd() and Logs
Every backend developer has been there: a request fails, something isn’t inserted into the database, and the codebase quickly turns into a sea of debugging statements:
dd($request->all());
dd($user);
dd($campaign);
Log::info($query);
Logs are added in controllers, services, repositories, queue workers, and event listeners. After hours of digging, you’re still confused because the real problem isn’t where you’re looking.
A Real‑World Example
A few months ago a team faced a strange issue with a simple form submission that should:
- Create a user
- Assign a campaign
- Generate a lead
- Push a welcome email into a queue
- Write an activity log
Randomly, some users were created without campaign data. Sometimes the queue job ran, sometimes it didn’t, and occasionally the transaction rolled back silently.
The first reaction was to sprinkle logs everywhere:
// Controllers
Log::info('Controller hit');
// Services
Log::info('Campaign assigned');
// Queue workers
Log::info('Email queued');
// Transactions
DB::beginTransaction();
The code became a forest of debugging statements, yet no clear answer emerged.
The Missing Insight: The Database Is the Single Source of Truth
No matter how beautiful your architecture is—whether you use Laravel, raw PHP, Node.js, Python, or Java—every query ends up in one place: MySQL. The database sees everything, and that realization changes how you debug.
Enabling the General Query Log
SET GLOBAL general_log = 'ON';
Then watch the live log:
tail -f /var/lib/mysql/hostname.log
You’ll see the exact sequence of statements:
INSERT INTO users ...
UPDATE campaigns ...
ROLLBACK;
In the example above, the ROLLBACK revealed that another process had locked a table for a few seconds—something no controller log could have shown.
Why Debugging Inside the Application Often Misses the Real Issue
A single request may involve:
- Queues
- Events
- Transactions
- Scheduled jobs
- Caching
- Background workers
- Third‑party APIs
By the time you debug from inside a controller, the actual problem may already be happening elsewhere (deadlock, lock wait, slow query, missing index, transaction conflict, etc.). MySQL already knows all of this.
Four Essential MySQL Features Every Backend Developer Should Know
1. General Query Log
SET GLOBAL general_log = 'ON';
Use case: Watch every query in real time, especially when a request touches multiple tables or when hidden ORM queries are suspected.
Remember: Disable it after debugging to avoid massive logs and performance impact.
SET GLOBAL general_log = 'OFF';
2. Slow Query Log
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- log queries slower than 1 second
Use case: Identify missing indexes, N+1 problems, huge table scans, and inefficient joins.
Example: A dashboard dropped from 12 seconds to under 800 ms after the slow query log exposed a missing index.
3. InnoDB Engine Status
SHOW ENGINE INNODB STATUS;
Use case: When you experience hanging requests, frozen queues, stuck inserts, or transaction conflicts, this command reveals the latest deadlock or lock‑wait information.
4. Triggers for Auditing
Create database‑level audit trails that are framework‑independent.
CREATE TRIGGER users_after_insert
AFTER INSERT ON users
FOR EACH ROW
INSERT INTO audit_logs(table_name, action_type)
VALUES ('users', 'INSERT');
Benefits: Automatic tracking of who changed data, when, which table, and what action—without relying on application logs.
Best Practices
- Enable logs only when needed. Turn on
general_logorslow_query_logtemporarily, investigate, then disable. - Monitor log size and performance. Permanent logging can quickly consume storage and degrade performance.
- Combine MySQL insights with application logs. Use database logs to pinpoint the root cause, then add targeted application logging if necessary.
- Leverage triggers for audit trails when you need reliable, framework‑agnostic change tracking.
By treating the database as the primary source of truth and using these built‑in MySQL tools, you can cut debugging time dramatically and avoid the endless cycle of sprinkling dd() and Log::info() throughout your code.