Cara Membuat Insiden Log Pada Laravel - CRUDPRO

Cara Membuat Insiden Log Pada Laravel

Pada kesempatan kali ini saya akan berbagi tulisan dengan anda, pada pembahasan kali ini yaitu tentang insiden log. Kesulitan untuk mencatat data yang berguna dan lebih sulit lagi dari sebelumnya untuk mencatat data yang berguna dengan cara yang membuatnya dapat diakses. Dalam kebanyakan kasus, hanya pengecualian yang dilemparkan yang akan dicatat. Ini benar-benar akar masalah jika anda harus request jika ingin melihat seluruh riwayat log, bukan hanya jejak tumpukan yang menyebabkan aplikasi tidak berjalan.

Bayangkan skenario ini. Pelanggan bersedia menggunakan situs Anda dan hanya mencoba mendapatkan halaman kesalahan besar di 500 server. Halaman tidak memiliki konteks dan tidak ada yang membantu memecahkan masalah. Jika mereka sendiri tidak terlalu teknis, mereka perlu menemukan cara untuk menjelaskan apa yang mereka lakukan ketika meminta jawaban dari dukungan perusahaan.

Sebaliknya, akan lebih baik jika dapat memberikan kode kesalahan kepada pelanggan jika terjadi kegagalan. Pengembang kemudian dapat memberikan kode kepada tim dukungan untuk disusun dengan data log dari request yang menghasilkan kesalahan. Memberikan poin instan untuk memulai penyelidikan Anda.

Saat mengembangkan dengan symfony, Anda dapat membuat handler Monolog "fingers crossed". Anda dapat melakukan hal yang sama dengan Laravel, tetapi pengaturan yang memperkenalkan fitur lain sedikit lebih mudah untuk diatur. Secara teori, ini harus bekerja untuk semua proyek Laravel 5.0+.

Pengaturan event listener Log Message

Pertama, Anda perlu mengumpulkan semua log Message yang dibuat. Sistem logging Laravel sudah menangani pengiriman ini, jadi yang harus Anda lakukan adalah membuat listener. Ini dapat dicapai dengan cara-cara berikut:

php artisan make:listener LoggingListener -e Illuminate\\Log\\Events\\MessageLogged

Kemudian edit listener seperti yang ditunjukkan pada contoh. Cukup tambahkan collection yang dapat mendorong peristiwa MessageLogged ini untuk digunakan nanti jika terjadi pengecualian fatal.

<?php

namespace App\Listeners;

use Illuminate\Log\Events\MessageLogged;

class LoggingListener
{
    /**
     * @var \Illuminate\Support\Collection
     */
    public $events;

    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        $this->events = collect([]);
    }

    /**
     * Handle the event.
     *
     * @param MessageLogged $event
     * @return void
     */
    public function handle(MessageLogged $event)
    {
        $this->events->push($event);
    }
}

Anda juga perlu mengubah EventServiceProvider, atau listen properti, untuk memastikan bahwa event MessageLogged dikirimkan ke listener LoggingListener baru.

<?php

namespace App\Providers;

use App\Listeners\LoggingListener;
use Illuminate\Log\Events\MessageLogged;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        'App\Events\Event' => [
            'App\Listeners\EventListener',
        ],
        MessageLogged::class => [
            LoggingListener::class
        ],
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        //
    }
}

Anda juga perlu membuat listener menjadi singletoon. Jika tidak, saat Anda mengakses event collected, Anda akan menerima listener dengan empty collection, dan Anda tidak akan dapat mengakses event collected. Yang perlu Anda tambahkan untuk ini adalah satu baris yang Anda tambahkan ke AppServiceProvider.

<?php

namespace App\Providers;

use App\Listeners\LoggingListener;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(LoggingListener::class);
    }
}

Perubahan handler exception

Anda sekarang memiliki koleksi acara MessageLogged. Anda perlu memodifikasi aplikasi handler exception Anda untuk melaporkan exception bersama dengan log dan mencetak kode kesalahan sehingga pengguna dapat melihatnya. Kelas ini terletak di app/Exceptions/Handler.php dan secara default memiliki dua metode, report dan render.

Untuk meringkas secara singkat kedua fitur ini, report didahulukan. Ini dimaksudkan untuk memungkinkan Anda mengirim exception ke beberapa service eksternal jika terjadi kegagalan. Lihat dokumentasi resmi untuk lebih lanjut tentang ini. Fitur rendering adalah cara untuk menampilkan halaman kesalahan kepada pengguna ketika terjadi kesalahan serius. Itu tidak mengubah fungsi rendering, tetapi Anda perlu mengganti metode renderHttpException kelas induk untuk mengubah proses.

<?php

namespace App\Exceptions;

use App\Listeners\LoggingListener;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Log\Events\MessageLogged;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\ViewErrorBag;
use Symfony\Component\HttpKernel\Exception\HttpException;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * The unique incident ID code
     *
     * @var string|bool
     */
    protected $incidentCode = false;

    /**
     * Report or log an exception.
     *
     * @param  \Exception  $exception
     * @return void
     */
    public function report(Exception $exception)
    {
        parent::report($exception);

        $this->incidentCode = str_random();

        $listener = $this->container->make(LoggingListener::class);

        $listener->events->map(function (MessageLogged $logged) {
            $logged->context = collect($logged->context)->map(function ($item) {
                if ($item instanceof \JsonSerializable) {
                    return $item;
                }

                return (string) $item;
            });
            return $logged;
        });

        Storage::disk('local')->put("incident\\{$this->incidentCode}.json", $listener->events->toJson(JSON_PRETTY_PRINT));
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $exception)
    {
        return parent::render($request, $exception);
    }

    /**
     * Render the given HttpException.
     *
     * @param  \Symfony\Component\HttpKernel\Exception\HttpException  $e
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function renderHttpException(HttpException $e)
    {
        $this->registerErrorViewPaths();

        if (view()->exists($view = "errors::{$e->getStatusCode()}")) {
            return response()->view($view, [
                'errors' => new ViewErrorBag,
                'exception' => $e,
                'incidentCode' => $this->incidentCode ?? false,
            ], $e->getStatusCode(), $e->getHeaders());
        }

        return $this->convertExceptionToResponse($e);
    }
}

Anda dapat melihat bahwa kami telah menambahkan mekanisme sederhana ke fungsi laporan untuk menyimpan laporan ke file json di disk lokal. Ini murni untuk tujuan demonstrasi. Peristiwa dapat digunakan untuk melakukan berbagai hal untuk memudahkan analisis. Saya juga memilih untuk menggunakan str_random yang disediakan oleh Laravel untuk menghasilkan ID unik, tetapi sejujurnya, Anda dapat menggunakan apa pun yang Anda suka. Pastikan itu cukup unik sehingga Anda tidak berakhir dengan banyak pengguna dengan kode yang sama.

Mengenai penambahan metode renderHttpException, kode contoh mirip dengan kode di kelas induk, kecuali bahwa itu tidak hanya meneruskan kesalahan dan exception variabel ke view, tetapi juga menyediakan variabel kode kesalahan.

Menambahkan halaman kesalahan untuk menampilkan kode

Tentu saja, bagian terakhir adalah kita memerlukan tampilan kesalahan yang menunjukkan kode kesalahan yang kita buat.

@extends('errors::layout')

@section('title', 'Error')

@section('message', 'Whoops, looks like something went wrong.'.(isset($incidentCode) ? ' Please contact support with incident code: '.$incidentCode : ''))

Kesalahan yang dilemparkan akan terlihat seperti tangkapan layar di bawah ini.

image

Ingatlah bahwa jika Anda tidak menyetel APP_DEBUG = true ke APP_DEBUG = false dalam file .env Anda saat ini, Anda tidak akan menerima pesan kesalahan produksi.

Pengujian

Ini adalah route kecil sederhana yang dapat Anda tambahkan ke tes route/web.php Anda bahwa laporan kesalahan sedang dibuat.

Route::get('/error-test', function() {
    Log::info('calling the error route');

    throw new \Exception('something unexpected broke');
});

Pengujian ini membuat dua peristiwa MessageLogged. Yang pertama adalah untuk jalur informasi, yang kedua adalah ketika Laravel menangkap pengecualian, dan akhirnya halaman kesalahan ditampilkan. Kode sampel akan membuat file json yang sesuai dengan storage/aplikasi/Insiden/ direktori proyek Anda.

Anda sekarang memiliki proses yang andal untuk melihat satu log kesalahan jika diperlukan. Ini hanyalah contoh dari apa yang sebenarnya dapat Anda lakukan. Tidak ada keraguan bahwa Anda dapat menggunakan mekanisme ini untuk membuat sistem yang sangat rinci untuk melacak insiden.

Kode demo yang berfungsi penuh dapat ditemukan di github.

sumber : https://medium.com/@SlyFireFox/laravel-how-to-make-incident-logs-d7fa88e48490