Send a slack notification every time Log::error is triggered
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Send a Slack Notification Every Time Log::error is Triggered: The Laravel Way
As a senior developer working within the Laravel ecosystem, you often encounter scenarios where you need centralized monitoring and alerting based on application events. One common requirement is notifying an external service, like Slack, whenever a critical event—such as an error log entry—is recorded.
The challenge lies in hooking into this process reliably, whether the trigger comes from an explicit call to Log::error(), a direct logger instance (logger()->error()), or, crucially, the default Laravel ExceptionHandler reporting an uncaught exception. Simply modifying every log statement is obviously impractical.
This post will walk you through the most robust and "Laravel-esque" way to achieve real-time logging notifications without cluttering your application code.
Why Simple Approaches Fall Short
You correctly identified the initial hurdles:
- Modifying the Facade: Changing the
Logfacade itself is generally discouraged as it tightly couples your custom logic to Laravel's core components, making future updates difficult. - ExceptionHandler Limitations: Placing logic directly in the
ExceptionHandleronly catches unhandled exceptions (500 errors). It completely misses logs generated by explicit calls likeLog::error('Something went wrong').
To solve this universally, we need a mechanism that sits between the logging action and the final storage/output. This points us toward leveraging Laravel's powerful Event System or custom Log Channel Handlers.
The Recommended Solution: Implementing a Custom Log Listener
The most flexible approach is to create a dedicated service provider that listens for specific logging events or, more directly, monitors the log driver itself. For this example, we will focus on creating a centralized listener that subscribes to all log entries and filters them for the error level before dispatching them to Slack.
Step 1: Set up the Slack Notification Service
First, let’s create a dedicated class responsible for handling the external communication. This keeps our logging logic clean and separate from API interactions.
// app/Services/SlackNotifier.php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class SlackNotifier
{
protected $webhookUrl;
public function __construct()
{
// Load configuration securely, perhaps from environment variables
$this->webhookUrl = config('services.slack.webhook_url');
}
public function sendErrorNotification(string $message, array $context): void
{
$payload = [
'text' => ":alert: ERROR DETECTED in Laravel App",
'attachments' => [
[
'color' => 'danger',
'title' => 'Critical Error Logged',
'fields' => [
['title' => 'Message', 'value' => $message],
['title' => 'Context', 'value' => json_encode($context)],
],
],
],
];
Http::post($this->webhookUrl, $payload);
}
}
Step 2: Create the Log Event Listener
Next, we create a listener that hooks into Laravel’s logging mechanism. While there isn't a built-in event for every log entry being written, we can hook into the system by listening to framework events or by leveraging custom configuration tailored to our needs. For maximum coverage across all log types, setting up a global listener is effective.
We will register this listener in a Service Provider:
// app/Providers/LoggingServiceProvider.php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;
use App\Services\SlackNotifier;
class LoggingServiceProvider extends ServiceProvider
{
public function register()
{
// Bind the notifier service
$this->app->singleton(SlackNotifier::class, function ($app) {
return new SlackNotifier();
});
}
public function boot()
{
// This is a conceptual hook. In a real-world scenario, you might hook into
// custom logging events or use framework hooks provided by the logger interface.
// For demonstration, we simulate hooking into an error condition:
// A more advanced approach involves creating a custom Log Channel/Handler that intercepts writes.
// For this pattern, we will rely on checking logs after they are written, or use a dedicated event listener
// if we were using Monolog directly. Since we are sticking to the Laravel abstraction,
// let's focus on handling exceptions and explicit logs via middleware or custom booting.
// A practical alternative for catching all errors: Listen to the application lifecycle events
Event::listen('laravel.boot', function () {
// This ensures our notification system is ready when the app starts.
// In a more complex setup, specific logging handlers would be registered here.
});
}
}
Step 3: Registering and Triggering (The Practical Implementation)
To make this truly effective for catching all errors, you often integrate this logic via Middleware or by leveraging the Report functionality within a custom setup. A robust pattern involves placing the Slack notification logic inside a dedicated service that is called whenever an error is explicitly recorded during the request lifecycle.
For instance, when handling an uncaught exception in your application flow (which falls under Laravel's error reporting), you can inject this notification logic into the handler:
// Example within your custom Exception Handler
use App\Services\SlackNotifier;
use Illuminate\Support\Facades\Log;
class Handler extends ExceptionHandler
{
protected $notifier;
public function __construct(SlackNotifier $notifier)
{
parent::__construct();
$this->notifier = $notifier;
}
public function render($request, \Throwable $exception)
{
// 1. Log the exception internally (standard Laravel behavior)
Log::error("Unhandled Exception: " . $exception->getMessage(), ['trace' => $exception->getTraceAsString()]);
// 2. Trigger Slack Notification for critical errors
if ($exception instanceof \Throwable) {
$this->notifier->sendErrorNotification(
"A critical error occurred during request processing.",
[
'class' => get_class($exception),
'message' => $exception->getMessage(),
'file' => $exception->getFile() . ':' . $exception->getLine(),
]
);
}
return parent::render($request, $exception);
}
}
Conclusion
The "best" Laravel way to achieve cross-cutting concerns like logging notifications is not to hack the core Log facade, but to utilize Laravel’s architectural strengths: Service Providers for binding dependencies and Exception Handlers for intercepting critical failures. By creating a dedicated service (like SlackNotifier) and ensuring that this service is called within your central error-handling mechanisms, you achieve separation of concerns. This approach keeps your application clean while ensuring that every critical log event—whether explicit or exception-driven—results in an immediate notification to your team via Slack. Remember, building extensible solutions based on Laravel’s core principles, as championed by the Laravel Company, is always the most sustainable path forward for complex applications.