Quando si sviluppa un’applicazione moderna, la registrazione (o logging) dovrebbe essere in cima alla lista delle priorità.

Il logging fornisce un modo per visualizzare la vostra applicazione sia in fase di sviluppo che di produzione, consentendo trasparenza e visibilità. Grazie a una corretta strutturazione dei registri, le applicazioni moderne possono diventare più facili da mantenere, in quanto possiamo identificare in modo proattivo i punti di guasto e i colli di bottiglia delle prestazioni della nostra applicazione.

Il framework Laravel è dotato di un robusto sistema di registrazione che gestisce tutti gli ostacoli legati alla configurazione di un sistema di logging correttamente strutturato. Il nuovo sistema di registrazione introdotto in Laravel 6.5 è molto potente e lo esploreremo in questo articolo.

In questo articolo analizziamo le basi del logging di Laravel e i motivi per cui dovreste usarlo nel vostro prossimo progetto. Parleremo in dettaglio del logging strutturato e del logging centralizzato. Inoltre, impareremo come implementare il logging in Laravel costruendo un’applicazione Todo.

Potrete trarre maggiori benefici da questo articolo se avete già acquisito le seguenti nozioni:

Cos’È il Logging di Laravel?

Il logging di Laravel riguarda il modo in cui Laravel gestisce la registrazione, ovvero la segnalazione automatica dei problemi, utilizzando un sistema di registrazione PHP virale chiamato Monolog. Tuttavia, grazie alla filosofia di Laravel di usare le librerie esistenti più diffuse per implementare le diverse funzionalità del framework, Laravel impiega Monolog per tutte le sue esigenze di logging.

Monolog è una libreria di registrazione PHP molto flessibile e popolare che possiamo configurare per inviare i log a file, socket, database e altri servizi web. Monolog fornisce un’interfaccia familiare per scrivere log da file di testo standard a servizi avanzati di gestione dei log di terze parti. Laravel di solito imposta Monolog in modo da utilizzare un file di configurazione di log standard.

Per maggiori informazioni su Monolog e le sue caratteristiche, consultate la documentazione ufficiale, poiché va oltre lo scopo di questo articolo.

Prima di immergerci nella configurazione e nell’implementazione dei registri di Laravel con Monolog, vediamo i motivi per cui usare i log di Laravel e le sue diverse tipologie.

Perché Usare i Registri di Laravel?

Perché i registri sono necessari?

Il manifesto della Twelve-Factor App considera il logging come uno dei punti critici di un’applicazione moderna, in quanto è fondamentale per le prestazioni e il monitoraggio.

I registri aiutano a comprendere nel dettaglio gli errori che si verificano in produzione e la loro origine. Inoltre, con una struttura di registrazione adeguata, possono mostrare l’utente specifico, l’azione che ha causato l’errore e la possibile soluzione per una più rapida correzione dei bug e per la manutenzione.

I registri strutturati sono un salvavita nelle applicazioni di produzione perché aiutano a risolvere i difetti e a risolvere i problemi in produzione. Inoltre, potete monitorare e raccogliere tutti i messaggi di log in tempo reale usando strumenti di log specializzati per l’analisi e la reportistica in tempo reale.

Per questi motivi, dovete fare del logging strutturato una priorità assoluta nel vostro prossimo progetto di applicazione moderna.

Vediamo una panoramica dei diversi stili di log disponibili.

Le Basi del Logging in Laravel

Imparare le basi del logging vi aiuterà a capire come Laravel gestisce la registrazione e come potete migliorare le vostre pratiche di logging strutturato.

Esaminiamo due concetti essenziali del logging per capire meglio come implementare le nostre procedure di logging.

Logging Strutturato in Laravel

Nello sviluppo del software, il logging strutturato consiste nell’implementare un formato di messaggio predeterminato e coerente per i log delle applicazioni. Questo formato permette di trattare i messaggi come dati che possono essere monitorati, manipolati e visualizzati molto meglio del normale formato di testo.

È necessario implementare un approccio strutturato ai log nello sviluppo di un’applicazione moderna perché i file di log sono un patrimonio essenziale per gli sviluppatori quando accade qualcosa di sbagliato all’applicazione in produzione.

Dal momento che Laravel usa Monolog, potete implementare rapidamente un logging strutturato configurando il logger per ricevere specifici tipi di informazioni, memorizzando i file di log in diversi formati e inviando i log a vari servizi di gestione dei log di terze parti per la visualizzazione.

Logging Centralizzato di Laravel

Un sistema di logging centralizzato prevede l’invio dei log da più fonti a soluzioni di Centralized Log Management (CLM) per facilitarne il consolidamento e la visualizzazione. Tuttavia, il CLM è una soluzione di logger specializzata che raccoglie i messaggi di log da diverse fonti e consolida i dati per facilitarne l’elaborazione e la visualizzazione.

Oltre alla raccolta dei dati, il CLM deve anche supportare l’analisi dei dati di log e una chiara presentazione dei dati dopo l’analisi.

Logging Strutturato vs. Logging di Base

Esaminiamo la differenza tra il logging strutturato e il logging di base (non strutturato) e perché dovreste usare il logging strutturato nel vostro progetto Laravel.

Logging di Base

Nel logging di base, i file di log sono archiviati in un formato grezzo con dati limitati per interrogare e identificare i singoli log.

Quando usano il logging di base, gli sviluppatori non potranno servirsi di strumenti analitici di terze parti per leggere, visualizzare e analizzare i log, a meno che non sviluppino uno strumento personalizzato o utilizzino uno strumento limitato che supporti il formato dei log.

Ci sono tre grandi ragioni per evitare di usare il logging di base:

  1. I sistemi di gestione dei log centralizzati non possono lavorare con i dati senza un supporto aggiuntivo.
  2. Per leggere e analizzare i dati di una soluzione di log di base è necessaria una soluzione personalizzata.
  3. Per gli amministratori può essere difficile leggere i dati di log di base perché sono grezzi e non strutturati.

Logging Strutturato

Il logging strutturato fa risparmiare tempo agli sviluppatori grazie all’utilizzo di strumenti di analisi dei log di terze parti open-source che supportano la struttura standard dei log per leggere, visualizzare e analizzare i log.

I log sono utili se contengono i dati corretti elencati di seguito, ed è questo l’obiettivo del logging strutturato. Possiamo usare i dati inclusi nel log strutturato per creare dashboard, grafici, diagrammi e qualsiasi altra visualizzazione utile per determinare lo stato di salute dell’applicazione.

Questi sono esempi di base delle informazioni che possiamo includere nei messaggi di log strutturati. Inoltre, potete personalizzare completamente i dati in base alle vostre esigenze.

Ecco alcuni esempi di dati che potete raccogliere con i log strutturati:

  1. La porta utilizzata per eseguire la funzione
  2. La data e l’ora in cui si è verificato l’evento
  3. Il nome utente o l’ID del cliente
  4. Una descrizione dell’evento (messaggio di log)
  5. Il protocollo utilizzato per eseguire la funzione
  6. Il luogo in cui si è verificato l’evento (indica l’API o l’applicazione in esecuzione)
  7. L’ID univoco dell’evento
  8. Il tipo di azione attivata (livello di log)

I log devono contenere dati sufficienti per visualizzare facilmente la soluzione o il motivo dell’evento di log. Inoltre, tenete presente che non dovreste memorizzare nei log tutti i tipi di informazioni, come le password o i dati sensibili.

Ora che abbiamo dato un’occhiata alle caratteristiche del logging di Laravel, passiamo all’implementazione del logging di Laravel costruendo un’applicazione dove il logging è in primo piano.

Come Implementare il Logging in Laravel con Todo App

Ora applicheremo quanto appreso finora creando un nuovo progetto Laravel e implementando il logging Laravel.

Se non avete mai usato Laravel prima d’ora, potete prima leggere cos’è Laravel o dare un’occhiata al nostro elenco di eccellenti tutorial su Laravel per iniziare.

Impostazione di Laravel

Per prima cosa, creeremo una nuova istanza di Laravel utilizzando il comando seguente. Potete consultare la documentazione ufficiale per saperne di più.

Aprite la vostra console e navigate fino al punto in cui memorizzate i vostri progetti PHP prima di eseguire i comandi qui sotto. Assicuratevi che Composer sia installato e configurato correttamente.

composer create-project laravel/laravel laravel-logging-app
cd laravel-logging-app // Change directory to current Laravel installation
php artisan serve // Start Laravel development server

Configurazione e Seeding del Database

Ora configureremo il nostro database, creeremo un nuovo modello Todo e inseriremo 200 dati falsi per i test.

Aprite il vostro client di database e create un nuovo database. Faremo lo stesso con il nome laravel_logging_app_db e poi riempiremo il nostro file .env con le credenziali del database:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_logging_app_db
DB_USERNAME=//DB USERNAME HERE
DB_PASSWORD=//DB PASSWORD HERE

Ora eseguiamo il seguente comando per creare contemporaneamente la migrazione e il modello Todo:

php artisan make:model Todo -mc

Aprite la migrazione appena creata che si trova in database/migrations/xxx-create-todos-xxx.php e incollate i seguenti codici:

<?php
use IlluminateSupportFacadesSchema;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreateTodosTable extends Migration
{
  /**
  * Run the migrations.
  *
  * @return void
  */
  public function up()
  {
    Schema::create('todos', function (Blueprint $table) {
      $table->id();
      $table->string('title');
      $table->text('description')->nullable();
      $table->boolean('is_completed')->default(false);
      $table->timestamps();
    });
  }
  /**
  * Reverse the migrations.
  *
  * @return void
  */
  public function down()
  {
    Schema::dropIfExists('todos');
  }
}

Potete creare i vostro todos con i dati di Faker imparando a creare i database in Laravel con Faker.

Panoramica di Monolog

Con Laravel Monolog, potete trasmettere e inviare log strutturati a diversi canali come email, Slack, file, socket, caselle di posta, database e vari servizi web. In Laravel, potete configurare i log da un unico file di configurazione situato in config/logging.php.

Il file di configurazione contiene dei driver di log predefiniti tra cui scegliere; il driver predefinito è stack che utilizza il canale single per registrare in un file laravel.log che si trova nella cartella storage/logs.

Dimostreremo il log strutturato usando un paio di driver di log di Laravel.

Laravel mette a disposizione una serie di metodi per interagire con i log, come dimostrato a breve nel file del controller TodosController.php.

Scrivere i Messaggi di Log nel Controller

Aprite il file del controller TodosController.php appena creato che si trova nella cartella app/Http/Controllers e incollate i seguenti codici:


<?php
namespace AppHttpControllers;
use AppModelsTodo;
use IlluminateHttpRequest;
use AppHttpControllersController;
use IlluminateSupportFacadesAuth;
use IlluminateSupportFacadesLog;
class TodosController extends Controller
{
  public function index(Request $request)
  {
    $todos = Todo::all();
    Log::warning('User is accessing all the Todos', ['user' => Auth::user()->id]);
    return view('dashboard')->with(['todos' => $todos]);
  }
  public function byUserId(Request $request)
  {
    $todos = Todo::where('user_id', Auth::user()->id)->get();
    Log::info('User is accessing all his todos', ['user' => Auth::user()->id]);
    return view('dashboard')->with(['todos' => $todos]);
  }
  public function show(Request $request, $id)
  {
    $todo = Todo::find($id);
    Log::info('User is accessing a single todo', ['user' => Auth::user()->id, 'todo' => $todo->id]);
    return view('show')->with(['todo' => $todo]);
  }
  public function update(Request $request, $id)
  {
    # Validations before updating
    $todo = Todo::where('user_id', Auth::user()->id)->where('id', $id)->first();
    Log::warning('Todo found for updating by user', ['user' => Auth::user()->id, 'todo' => $todo]);
    if ($todo) {
      $todo->title = $request->title;
      $todo->desc = $request->desc;
      $todo->status = $request->status == 'on' ? 1 : 0;
      if ($todo->save()) {
        Log::info('Todo updated by user successfully', ['user' => Auth::user()->id, 'todo' => $todo->id]);
        return view('show', ['todo' => $todo]);
      }
      Log::warning('Todo could not be updated caused by invalid todo data', ['user' => Auth::user()->id, 'todo' => $todo->id, 'data' => $request->except('password')]);
      return; // 422
    }
    Log::error('Todo not found by user', ['user' => Auth::user()->id, 'todo' => $id]);
    return; // 401
  }
  public function store(Request $request)
  {
    Log::warning('User is trying to create a single todo', ['user' => Auth::user()->id, 'data' => $request->except('password')]);
    # Validations before updating
    $todo = new Todo;
    $todo->title = $request->title;
    $todo->desc = $request->desc;
    $todo->user_id = Auth::user()->id;
    if ($todo->save()) {
      Log::info('User create a single todo successfully', ['user' => Auth::user()->id, 'todo' => $todo->id]);
      return view('show', ['todo' => $todo]);
    }
    Log::warning('Todo could not be created caused by invalid todo data', ['user' => Auth::user()->id, 'data' => $request->except('password')]);
    return; // 422
  }
  public function delete(Request $request, $id)
  {
    Log::warning('User is trying to delete a single todo', ['user' => Auth::user()->id, 'todo' => $id]);
    $todo = Todo::where('user_id', Auth::user()->id)->where('id', $id)->first();
    if ($todo) {
      Log::info('User deleted a single todo successfully', ['user' => Auth::user()->id, 'todo' => $id]);
      $todo->delete();
      return view('index');
    }
    Log::error('Todo not found by user for deleting', ['user' => Auth::user()->id, 'todo' => $id]);
    return; // 404
  }
}

All’interno di ogni metodo di TodoController, abbiamo aggiunto la facciata Log con un livello di log specifico per definire il tipo di errore che vogliamo inviare. Di seguito è riportato un esempio di utilizzo della facciata Log nel metodo store.

public function store(Request $request)
{
  Log::warning('User is trying to create a single todo', ['user' => Auth::user()->id, 'data' => $request->except('password')]);
  # Validations before updating
  $todo = new Todo;
  $todo->title = $request->title;
  $todo->desc = $request->desc;
  $todo->user_id = Auth::user()->id;
  if ($todo->save()) {
    Log::info('User create a single todo successfully', ['user' => Auth::user()->id, 'todo' => $todo->id]);
    return view('show', ['todo' => $todo]);
  }
  Log::warning('Todo could not be created caused by invalid todo data', ['user' => Auth::user()->id, 'data' => $request->except('password')]);
  return; // 422
}

Formattazione dei Messaggi di Log

Supponiamo che vi sentiate a vostro agio con il sito LineFormatter utilizzato da Laravel, che fa un ottimo lavoro nel fornire messaggi leggibili e utili.

In questo caso, potete creare facilmente un oggetto formattatore personalizzato che si adatti al vostro caso d’uso e usarlo in tutta l’applicazione.

La documentazione ufficiale di Monolog fornisce un elenco completo dei formattatori disponibili e potete facilmente crearne uno personalizzato.

In Laravel, potete impostare uno qualsiasi dei driver in modo che usi il vostro formattatore personalizzato aggiungendolo all’elenco, come indicato di seguito, all’interno del file di configurazione situato in config/logging.php:

'daily' => [
  'driver' => 'daily',
  'path' => storage_path('logs/laravel.log'),
  'level' => env('LOG_LEVEL', 'debug'),
  'days' => 14,
  'formatter' => MonologFormatterHtmlFormatter::class,
  'formatter_with' => [
    'dateFormat' => 'Y-m-d',
  ]
],

L’esempio precedente aggiunge un formattatore personalizzato MonologFormatterHtmlFormatter al driver daily utilizzando le chiavi formatter e formatter_with nella configurazione del canale daily per cambiare il formato delle date.

Inviare i Log a Diversi Canali

Con l’aiuto di Monolog, Laravel può inviare i log a diversi canali e a più canali contemporaneamente.

Vediamo come inviare i log al nostro canale Slack seguendo questi semplici passaggi. Cambiate il canale di log predefinito in Slack e aggiungete l’URL di Slack Webhook nel vostro file .env.

LOG_CHANNEL=slack
LOG_SLACK_WEBBHOOK_URL= Slack_webhook_url_here

Successivamente, testate la vostra configurazione registrando un messaggio nella vostra applicazione utilizzando la facciata Log come quella mostrata di seguito:

Log::debug("The API instance is on fire caused by:", ['user' => 1])

Potete aprire il vostro canale Slack per verificare se l’errore è stato stampato nel canale desiderato che avete specificato durante la generazione dell’URL Webhook.

Riepilogo

La registrazione è importante quanto qualsiasi altro fattore della vostra applicazione, se non di più. Per questo motivo, il manifesto della Twelve-Factor App la suggerisce come uno degli aspetti più critici di ogni applicazione moderna.

Con un processo di registrazione efficace, potete facilmente leggere, vedere e visualizzare gli errori e i difetti che si verificano nella vostra applicazione pronta per la produzione. A tal fine, è importante implementare un logging strutturato nella vostra applicazione fin dall’inizio del progetto.

In questo articolo abbiamo esplorato la registrazione, o logging, di Laravel e i motivi per cui dovreste usarla nel vostro prossimo progetto. Abbiamo discusso in dettaglio sia il logging strutturato che il logging centralizzato. Inoltre, abbiamo imparato come implementare il logging in Laravel costruendo un’applicazione Todo.

Come pensate di implementare il logging nella vostra prossima applicazione? Fatecelo sapere nella sezione dei commenti.

Solomon Eseme

I am a Software Engineer and Content Creator who is geared toward building high-performing and innovative products following best practices and industry standards. I also love writing about it at Masteringbackend.com. Follow me on Twitter, LinkedIn, and About Me