How To Get Real Time App Crashes From Your Laravel App
Given Ncube
You may have written all the tests, followed the SOLID principles, or whatever is hot these days but when your app is in production and getting real users things get a little wild, bugs may go unnoticed, runtime errors you may never have expected. In this post, I'm going to show you how to set up a real time error reporting system in Laravel that will notify you as soon an error occurs in your application. There are already other robust tools for this like Flare, Sentry but these services are paid and may not be the best solution for that side project you may never launch.
So the idea is simple, listen for the Illuminate\Log\Events\MessageLogged
event, send the details of the error to the developers for debugging, thanks to Laravel's error handling it just got easier.
Here, we're going to send reports via Telegram as soon as an error occurs but you can use email, Slack, or something else. To do that were are going to use Laravel Notification Channels to send the notification.
The first step is to create an event listener to listen for Illuminate\Log\Events\MessageLoged
. Open your EventServiceProvider
in the $listen
array append the following code.
use Illuminate\Log\Events\MessageLogged;
use App\Listeners\ReportIncident;
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
MessageLogged::class => [
ReportIncident::class,
]
];
Then run this command to generate the event
php artisan event:generate
Then generate the notification to report errors
php artisan make:notification AppCrashed
Now in your ReportIncident.php
in the handle method add the following
use App\Notifications\AppCrashed;
User::where('email', 'youradminusermail')->first()->notify(new AppCrashed($event));
So we're notifying the admin user of the incident
Now for the AppCrashed
add this in the constructor to accept the MessageLogged
event
use Illuminate\Log\Events\MessageLogged;
private $logged;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct(MessageLogged $logged)
{
$this->logged = $logged;
}
Now modify the via
method to send the notification via Telegram
use NotificationChannels\Telegram\TelegramMessage;
public function via($notifiable)
{
return [TelegramChannel::class, 'database'];
}
As you can see we're importing that TelegramMessage
class but we don't have it yet. Talk to @BotFather
on Telegram and create a new bot then follow the setup instructions here. If you now have your bot API key, let's Install the Telegram Notification Channel
composer require laravel-notification-channels/telegram
Make sure you've all your environment variables setup as described in the documentation.
Next, add this method
/**
* Get the telegram representation of the notification.
*
* @param mixed $notifiable
* @return \NotificationChannels\Telegram\TelegramMessage;
*/
public function toTelegram($notifiable)
{
return TelegramMessage::create()
->to('telegram-chat-or-user-id')
->content("Hi admin, \nsomething terrible has happened.\n\n*App name:* " . config('app.name') . "\n\n*Page:* " . url()->current() . "\n\n*Exception Message:* " . $this->logged->message . "\n\n*Severity:* " . $this->logged->level)
->button('View Incident', 'www.yourdomain.com/admin/incidents');
}
To get the Telegram chat or user id send a message to your bot or create a channel then send a message in the channel. After that head over to api.telegram.org/bot<you-bot-api-key>/getUpdates
and look at the chat or user id of the message.
We're almost done, as you may have noticed earlier in the via
method we also added the database channel let's set that up so that we can view more information about the error later on.
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
$logged = collect($this->logged->context)->map(function ($error) {
if ($error instanceof \JsonSerializable) {
return $error;
}
return (string) $error;
});
return [
'logged' => $logged->toJson(JSON_PRETTY_PRINT),
'message' => $this->logged->message,
'level' => $this->logged->level,
'page' => url()->current(),
'app' => config('app.name'),
];
}
This method is simply going to store the incident in the database for future analysis. the logged
key stores array of JSON or string representation of the context values in this case it may be the stack trace. Go ahead and create a route in your application that displays all the info above.
Now if an error happens in your app, you'll get this in Telegram
You can get creative and improve this, I hope this can help you ship with fewer bugs.
[convertkit=2908863]