Posílání emailu při výjimce

Vytvořili jste novou Laravel aplikaci pro vašeho klienta nasadili jste ji na produkční server. Všechno funguje v pořádku do doby než má zákazník problém s aplikací z důvodu nějakého bugu. Okamžitě opouští aplikaci a to samé se děje i s dalšími zákazníky do té doby, než se o problému dozvíte. Opravíte bug a všechno je zase v pořádku. Co když ale budete okamžitě upozorněni emailem (či jinou službou) o vzniklém problému a opravíte ho tak co nejdříve? V Laravelu to jde snadno a v tomto článku se dozvíte jak na to.

V Laravelu jsou všechny výjimky zachyceny třídou App\Exceptions\Handler. Tato třída obsahuje dvě metody - report a render. V rámci tohoto článku nás zajímá metoda report, která se používá k logování výjimek nebo jejich posílání na externí služby jako jsou Bugsnag nebo Sentry. Defaultně metoda report jednoduše posílá výjimku dále na "base" třídu kde je výjimka zalogována. Nicméně ji můžeme také využít k posílání emailu vývojářům společně s vyhozenou výjimkou.

/**
 * Report or log an exception.
 *
 * Vhodne misto pro posilani vyjimek emailem.
 *
 * @param  \Exception  $exception
 * @return void
 */
public function report(Exception $exception)
{
    if ($this->shouldReport($exception)) {
        $this->sendEmail($exception); // sends an email
    }

    return parent::report($exception);
}

/**
 * Posilani emailu vyvojarum ohledne vyjimky.
 *
 * @param  \Exception  $exception
 * @return void
 */
public function sendEmail(Exception $exception)
{
    // sending email
}

Ve třídě využíváme metodu shouldReport (nacházející se v Illuminate\Foundation\Exceptions\Handler ) k ignorování výjimek, které jsou v proměnné $dontReport.

Každý typ emailu posílaný aplikací je v Laravelu reprezentován jako "mailable" třída. Takže si vytvoříme naši mailable třídu příkazem make:mail:

$ php artisan make:mail ExceptionOccured

Tím se vytvoří třída ExceptionOccured v adresáři app/Mail.

Samotné posílání emailu nevyřeší problém. Potřebujeme také celou cestu výjimky (full stack trace) a pro tento případ využijeme Symfony Debug komponenty.

public function sendEmail(Exception $exception)
{
    try {
        $e = FlattenException::create($exception);

        $handler = new SymfonyExceptionHandler();

        $html = $handler->getHtml($e);

        Mail::to('developer@gmail.com')->send(new ExceptionOccured($html));
    } catch (Exception $ex) {
        dd($ex);
    }
}

Pro jistotu jsme použili blok try/catch abychom se vyhnuli nekonečné smyčce kdyby třída Mail selhala. Také se ujistěte, že v hlavičce máte následující třídy:

use Mail;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\Debug\ExceptionHandler as SymfonyExceptionHandler;

Poté doplňte třídu ExceptionOccured o následující obsah:

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class ExceptionOccured extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * The body of the message.
     *
     * @var string
     */
    public $content;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($content)
    {
        $this->content = $content;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('emails.exception')
                    ->with('content', $this->content);
    }
}

V nově vytvořeném pohledu emails.exceptions přidejte výpis proměnné:

{!! $content !!}

Nyní kdykoliv se v aplikaci vyhodí výjimka, dostanete email s celou cestou výjimky. Originální autor tohoto návodu také vytvořil Laravel balíček squareboat/sneaker, který již všechno nastaví víceméně sám a vy se tak můžete soustředit na řešení vzniklého problému.

Některé z výhod balíčku sneaker jsou:

Pokud by jste se chtěli podívat na kompletní kód, pak projekt najdete zde na Github.

Zdroj: laravel-news.com