Avoid Double-Reporting Errors (Log vs Throw)

📖 2 minutes read

Have you ever noticed one production failure turning into two (or more) alerts?

A frequent cause is double-reporting the same problem: your code logs an error and throws an exception, while your error tracker captures both the log entry and the unhandled exception.

The problem pattern

This is the classic “log and throw” antipattern:

use Illuminate\Support\Facades\Log;

try {
    $result = $service->run();
} catch (\Throwable $e) {
    Log::error('Service failed', ['exception' => $e]);
    throw $e;
}

Depending on your monitoring setup, that can create:

  • One event for the log entry
  • Another event for the unhandled exception

A cleaner approach

Decide which signal is the source of truth:

  • If you’re going to rethrow: skip explicit logging and just add context where you catch it.
  • If you handle it: log it (with context) and do not rethrow.

Example: add context, then rethrow without logging:

try {
    $result = $service->run();
} catch (\Throwable $e) {
    // Attach context for your exception handler / error tracker.
    // (How you do this depends on your app; keep it lightweight.)
    throw new \RuntimeException('Processing failed', 0, $e);
}

Bonus: use a correlation id

When you do log, include a request/job correlation id so you can trace everything without multiplying alerts.

Log::withContext([
    'correlation_id' => request()->header('X-Correlation-Id') ?? (string) \Illuminate\Support\Str::uuid(),
]);

The end goal isn’t “less logging” — it’s one clear alert per real failure, with enough context to debug fast.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *