Monolog is the de facto standard logging library for PHP and comes out of the box in the most popular PHP frameworks, such as Laravel and Symfony. It implements PSR-3 - a common interface for logging libraries defined by PHP-Fig. Type-hinting Psr\Log\LoggerInterface
in your application enables interoperability, allowing you change the logging library for another that implements PSR-3 without too much headache. This library is already included in Symfony 3 by default, so you will be able to intercept exceptions in production and send an email with the details about the failure.
In this article we'll show you how to configure monolog to send emails about critical errors automatically using Swift Mailer.
Requirements
You will need to have installed the following packages in your Symfony application (they're normally already installed, however check that they're installed in your composer.json
):
- Swift Mailer (
symfony/swiftmailer-bundle
). - Monolog (
symfony/monolog-bundle
).
After checking that the previous tools are installed on your app, proceed with the configuration of the automatic error reporting via email.
1. Configure App Mailer (Swift Mailer)
In order to send the error email, Monolog will need the default mailer configured with Swiftmailer in your application. This can be easily done in your config.yml
and providing the email credentials, the transport mode, encryption etc (more information about swiftmailer configuration here):
# app/config/config.yml
# Swiftmailer Configuration
# Note: the setup may change according to your email provider
# for example, with zoho, the configuration for the mailer would
# be something like this.
swiftmailer:
transport: smtp
host: smtp.zoho.com
username: [email protected]
password: password123
port: 465
encryption: ssl
spool: { type: memory }
As mentioned, be sure that the mailer works previously because Monolog won't throw any exception if the mailer isn't configured correctly.
2. Configure Monolog Email Report
For sanity reasons, you want the email report automatically activated only in production environment, so you need to enable monolog in the config_prod.yml
file. You will need as well, to send the exception via email and write it to the logs, so you need to be careful with the configuration of Monolog in production:
# app/config/config_prod.yml
imports:
- { resource: config.yml }
monolog:
handlers:
main:
type: fingers_crossed
action_level: critical
handler: grouped
grouped:
type: group
members: [streamed, deduplicated]
streamed:
type: stream
path: '%kernel.logs_dir%/%kernel.environment%.log'
level: debug
deduplicated:
type: deduplication
handler: swift
swift:
type: swift_mailer
from_email: '[email protected]'
# Or multiple receivers:
# to_email: ['[email protected]', '[email protected]']
to_email: '[email protected]'
subject: 'An Error Occurred! %%message%%'
level: debug
formatter: monolog.formatter.html
content_type: text/html
The mail handler is a fingers_crossed handler which means that it is only triggered when the action level, in this case critical is reached (5xx HTTP code errors). If this level is reached once, the fingers_crossed handler will log all messages regardless of their level. The handler setting means that the output is then passed onto the deduplicated handler.
The messages are then passed to the swift handler. This is the handler that actually deals with emailing you the error. The settings for this are straightforward, the to and from addresses, the formatter, the content type and the subject. The previous snippet is the best configuration to get the errors still logged on the server and emailed as well.
3. Causing intentional exception to test in production
After registering the email report of monolog, you need to test if it works. You can test in your local environment accessing your app from the production environment, however don't forget to clear the cache of the project previously using:
php bin/console cache:clear
In our example, we'll trigger a simple exception from a controller in the index action:
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class PagesController extends Controller
{
public function indexAction()
{
// Test non-existent class
throw new Exception("That's too bad !");
}
}
After accesing the index action in your browser, monolog will send the email in the background and will display a 500 error in the browser. Now if you check your mail, you will see the exception message, the class and the file where the exception was triggered, the line etc:
Now you will be able to debug and fix those errors without asking to the user what he did to replicate the issue.
Happy coding !