
Logging Is a Must — So You Don’t Have to Play Psychic When Errors Happen

Imagine this :
A new feature just went live. Then a user reports: “Why can’t I check out?” You try it locally — it works. You check the user’s browser console — nothing.
Without logs, all you can do is guess — like a psychic trying to read errors from the sky. 😅
[2025-06-04 10:15:22] production.INFO: [log_id: 6a9c3e21-778e-49d4-9c98-cbba5ea0c841] User login berhasil. user_id=101 ip=103.12.5.77 url=/api/login
[2025-06-04 10:20:07] production.WARNING: [log_id: d57ab8fc-45c1-4e82-9c7d-07b8e446acf6] Permintaan aneh terdeteksi. user_id=101 ip=103.12.5.77 url=/api/products?sort=DROP+TABLE
[2025-06-04 10:21:43] production.ERROR: [log_id: a34a89df-25b9-4a57-b210-dab32e68f4c9] Checkout gagal. user_id=101 ip=103.12.5.77 url=/api/checkout error=Payment gateway timeout
[2025-06-04 10:22:00] production.INFO: [log_id: 55f3bc3d-7ed3-4cdd-b2e3-90cdb1d2c024] Notifikasi email berhasil dikirim. user_id=101 [email protected]
Logging is an automatic record of what happens inside your application. If you have clean and complete logs, you can :
- Check the transaction ID
- See who the user is
- View error messages, trace, and IP address
- Instantly identify the failure point
Logging isn’t just a bonus. Logging is your lifeline when debugging. Without logs, you’ll end up going in circles, unsure where to start. With logs, you can pinpoint the problem quickly — no panic, no guesswork.
1. Log Every Exception with a Unique ID
When an exception occurs, it should be logged with a unique ID (UUID). Why?
With a unique ID for every error, the frontend team can simply pass that ID to the backend team. The backend team can then search the logs using that ID — no need to dig through the browser’s stack trace.
use Illuminate\Support\Str;
try {
// proses penting
} catch (Exception $e) {
$logId = Str::uuid();
Log::error("[$logId] Gagal memproses checkout", [
'user_id' => auth()->id(),
'ip' => request()->ip(),
'url' => request()->fullUrl(),
'message' => $e->getMessage(),
]);
return response()->json([
'message' => 'Terjadi kesalahan, silakan hubungi admin.',
'log_id' => $logId,
], 500);
}
Why should it go to a log file? Because :
- In production, you must never show stack traces to users (it’s a security risk).
- Log files are the only source of truth for developers.
2. Include Request Context
Don’t just log the error message. Also include :
- user_id → who’s using it?
- ip → where is it coming from?
- url → which endpoint is affected?
- params → what’s in the request body?
The more context you have, the faster you can perform root cause analysis.
3. Use Structured Logging (Not String Concatenation)
Don’t do it like this :
// ❌ string biasa
console.log("User gagal login: " + userId + ", error: " + err.message);
Do it like this :
// ✅ structured
console.error("Login gagal", {
userId: user.id,
error: err.message,
ip: req.ip,
path: req.originalUrl
});
Structured logs make it easier to :
- Search
- Index using tools like ELK or Datadog
- Be read by both humans and machines
Common Log Format
Whether your logs are in plain text (.log) or JSON, here’s the information you should always include :
- timestamp → when it happened
- level → ERROR, INFO, WARN, etc.
- message → what happened
- log_id → unique ID
- user_id, ip, url → context
- ❗ Never log passwords, tokens, credit card numbers, or other sensitive data.
4. Rotate Log Files Regularly to Avoid Overflow
Logs can grow quickly.
If left unchecked :
- Your disk can fill up
- The application may crash
Solutions :
- In Laravel: set logging.php to daily
- On Linux: use logrotate
- Add disk usage monitoring
Note: This article was inspired by a LinkedIn post by Mayank A., which discusses best practices in software development. You can read the original version Here.