Bununla ilgili daha önce bir çalışmam oldu ama hiç üzerinde durma fırsatım olmamıştı. Ayrıntılı bir makale bilmiyorum ama buraya yazacaklarımdan bir tane makale çıkartıp yayınlayacağım. Tekrar konusu açılırsa en azından elimizde bir makale olur.
Dokümanlarda fazla ayrıntıya yer verilmiyor, her şeyi yazmak mümkün değil. Bazı şeyleri sizin araştırıp bulmanız gerekiyor. Bunları araştırırken de PHP, tasarım desenleri ve kod okuma konusunda beceri ve bilginiz size yardımcı olur. Bir şeyi bulmakta zorluk çekiyorsanız orada eksiğiniz olduğunu düşünüp üzerine gitmeniz lazım.
Anlatacaklarımın bazısı dokümanlarda var, bazısı yok.
config/logging.php içerisinde stack kanalı (channel) var. Bu özel bir kanal, birden fazla kanalı birlikte kullanmamıza olanak tanıyor. Örneğin:
'stack' => [
'driver' => 'stack',
'channels' => ['single','daily'],
'ignore_exceptions' => false,
],
şeklinde yaptığınızda hata meydana geldiğinde hem single hem de daily kanallarında belirtilen işlemler gerçekleşecek demektir.
Önce emergency seviyesinde hataları bize mail atacak bir kanal yazalım ve bunu stack kanalına ekleyelim. Ayrıca daily kanalını da kullanmak istiyorsunuz, o zaman şöyle olacak:
'stack' => [
'driver' => 'stack',
'channels' => ['daily', 'emergency_mail'],
'ignore_exceptions' => false,
],
'emergency_mail' => [
'driver' => 'monolog',
'level' => 'emergency',
'handler' =>null
]
Emergency seviyesinde hata meydana geldiğinde emergency_mail kanalı devreye girecek fakat ortada henüz bir mail gönderme mantığı yok. Bunun için handler anahtarını kullanacağız. Hata yakalandığında handler devreye giriyor.
Şu linkte kullanabileceğimiz handler'lar var:
https://github.com/Seldaek/monolog/tree/master/src/Monolog/Handler
Bu listede şu an için ihtiyacımız olan MailHandler.php:
https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/MailHandler.php
MailHandler kodlara bakarsanız eğer iki yer önemli:
abstract class MailHandler extends AbstractProcessingHandler
abstract protected function send(string $content, array $records): void;
MailHandler sınıfı abstract ve bir de abstract protected send yöntemi var. Soyut sınıfları direk yükleyemezsiniz, extends ile genişletip kendi sınıfınızı kullanmanız lazım. Soyut sınıf interface ise gerçeklemeniz (implementation) lazım Ayrıca içerisindeki soyut yöntemleri (send) de kendi sınıfınızda oluşturmanız gerekiyor. Kod bize bu sınıfı genişlet ve send yöntemi içerisinde mailini gönder, bak sana $content şeklinde hata içeriğini ve $records şeklinde de belki kullanmak istersin diye hatanın dizi versiyonunu veriyorum, gerisi sana kalmış diyor.
Biz de app/MonologHandlers/IlluminateMailHandler.php şeklinde bir handler oluşturalım. PSR-4 kullandığımız için siz app klasörü içerisinde istediğiniz gibi projenizi organize edebilirsiniz, isimlere ve yerlere fazla takılmayın:
<?php
namespace App\MonologHandlers;
use Monolog\Handler\MailHandler;
class IlluminateMailHandler extends MailHandler
{
/**
* @inheritDoc
*/
protected function send(string $content, array $records): void
{
// Mail gönder...
}
}
Mail göndermek için de (madem Laravel yolu istiyoruz, vanilla istemiyoruz) bir tane mailable oluşturalım:
php artisan make:mail EmergencyErrorOccurred
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class EmergencyErrorOccurred extends Mailable
{
use Queueable, SerializesModels;
/**
* @var string
*/
public $content;
/**
* @var array
*/
public $records;
/**
* Create a new message instance.
*
* @param string $content
* @param array $records
*/
public function __construct(string $content, array $records)
{
$this->content = $content;
$this->records = $records;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.emergency-error');
}
}
Kodda görüldüğü gibi bir de resources/views/emails/emergency-error.blade.php şablonuna ihtiyacımız var. İçerisine kurucu yöntem ile $content ve $records değişkenlerini aynı isimle gönderiyoruz. Ben kısa tuttum, şablonun içeriği sadece şu:
{{ $content }}
IlluminateMailHandler::send() yöntemini düzenleyelim:
/**
* @inheritDoc
*/
protected function send(string $content, array $records): void
{
Mail::to('mailadresim@gmail.com')->send(new EmergencyErrorOccurred($content, $records));
}
Şimdi bu handler'ı emergency_mail kanalına ekleyelim:
'emergency_mail' => [
'driver' => 'monolog',
'level' => 'emergency',
'handler' => \App\MonologHandlers\IlluminateMailHandler::class
]
Bu şekilde sorununuzu çözmüş olduk. Artık hatalar hem günlük olarak dosyaya loglanacak hem de emergency seviyesinde bir hata meydana gelirse mailadresim@gmail.com adresine mail atacak. Bu aşamalarda kuyruk ile işlemi arka planda yaptırmak isteyeceksiniz muhtemelen.
Dosyaların 7 günde bir başka dizine taşınması
Bunu görev zamanlayıcı ile kolayca halledebileceğinizi düşünüyorum:
https://laravel.com/docs/6.x/scheduling
Görev zamanlayıcı ile kullanmak için de bir tane taşıma işlemini yapacak MoveDailyLogs gibi bir konsol komutu yazın:
https://laravel.com/docs/6.x/artisan#generating-commands
Şu şekilde halledersiniz:
$schedule->command(MoveDailyLogs::class)->weekly();