錯誤與日誌

簡介

當你開始一個新的 Laravel 專案時,Laravel 已經幫你設定好錯誤和例外的處理。另外,Laravel 也整合了 Monolog 日誌函式庫,Monolog 支援和提供多種強大的日誌處理。

設定

錯誤細節

你的應用程式透過 config/app.php 設定檔中的 debug 設定選項來控制瀏覽器顯示錯誤的細節。預設情況下,此設定選項是參照於儲存在 .env 檔案的 APP_DEBUG 環境變數。

在本機開發的時候,你應該將 APP_DEBUG 環境變數設定為 true。在你的上線環境中,這個值應該永遠為 false

日誌模式

Laravel 提供立即可用的 singledailysyslogerrorlog 日誌模式。例如,如果你想要每天儲存一個日誌檔,而不是單一的檔案,你可以簡單地在 config/app.php 設定檔內設定 log 變數:

'log' => 'daily'

自訂 Monolog 設定

如果你想要完全控制 Monolog,你可以使用應用程式的 configureMonologUsing 方法設定你的應用程式。你應該在 bootstrap/app.php 檔案回傳 $app 變數之前呼叫這個方法:

$app->configureMonologUsing(function($monolog) {
    $monolog->pushHandler(...);
});

return $app;

錯誤處理

所有的例外處理都是透過 App\Exceptions\Handler 類別。這個類別包含了兩個方法:reportrender。我們將研究這些方法的細節。

報告方法

report 方法用來記錄例外或將它們發送到像是 BugSnag 的外部服務。預設情況下,當例外被記錄時,report 方法只是簡單的傳送例外到基底的類別。然而,你可以自由的記錄例外。

例如,如果你需要以不同的方式報告不同類型的例外,你可以使用 PHP instanceof 比較運算子:

/**
 * 報告或記錄一個例外。
 *
 * 這裡是個把例外送至 Sentry、Bugsnag 等等的好地方。
 *
 * @param  \Exception  $e
 * @return void
 */
public function report(Exception $e)
{
    if ($e instanceof CustomException) {
        //
    }

    return parent::report($e);
}

藉由類型忽略例外

例外處理中的 $dontReport 屬性是一個陣列,包含不需要被記錄的例外類型。預設情況下,由 404 錯誤導致的例外結果並不會被記錄到日誌檔案。你可以根據你的需求增加其他例外類型到這個陣列。

呈現方法

render 方法負責將給定的例外轉換成 HTTP 回應再傳送到瀏覽器。預設情況下,例外會被傳送到基底類別並幫你產生回應。然而,你可以自由的檢查例外類型或回傳客製化的回應:

/**
 * 呈現例外到 HTTP 回應。
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $e
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $e)
{
    if ($e instanceof CustomException) {
        return response()->view('errors.custom', [], 500);
    }

    return parent::render($request, $e);
}

HTTP 例外

有一些例外是描述來自伺服器的 HTTP 錯誤碼。例如,這可能是個「找不到頁面」錯誤(404),「未授權錯誤」(401),或甚至是開發者導致的 500 錯誤。你可以使用以下的方法,在你的應用程式任何地方產生回應:

abort(404);

abort 方法透過錯誤處理,將會立即引發例外,並且呈現錯誤。或者,你可以提供回應的文字訊息:

abort(403, 'Unauthorized action.');

你可以在請求的生命週期中任何時間點使用這個方法。

客製化 HTTP 錯誤頁面

Laravel 讓你可以簡單的對於各種不同的 HTTP 狀態碼回傳客製化的錯誤視圖。例如,如果你想要自訂 HTTP 404 狀態碼的錯誤視圖,建立一個 resources/views/errors/404.blade.php。應用程式將會使用這個視圖處理所有發生的 404 錯誤。

在這個目錄下的視圖,命名應該匹配對應到 HTTP 狀態碼。

日誌

Laravel 日誌工具在強大的 Monolog 函式庫上提供一層簡單的功能。Laravel 預設為應用程式建立每天的日誌檔並儲存在 storage/logs 目錄。你可以使用 Log facade 寫入資訊到你的日誌:

<?php

namespace App\Http\Controllers;

use Log;
use App\User;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * 顯示給定使用者的個人資料。
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        Log::info('Showing user profile for user: '.$id);

        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

日誌工具提供了定義在 RFC 5424 的八個級別: emergencyalertcriticalerrorwarningnoticeinfodebug

Log::emergency($error);
Log::alert($error);
Log::critical($error);
Log::error($error);
Log::warning($error);
Log::notice($error);
Log::info($error);
Log::debug($error);

上下文訊息

傳入上下文相關的資料陣列到日誌方法裡。此上下文的相關資料會進行格式化並顯示在日誌訊息:

Log::info('User failed to login.', ['id' => $user->id]);

存取 Monolog 底層實例

Monolog 有許多各式的附加處理方法讓你使用在日誌上。如果有需要,你可以存取 Laravel 底層的 Monolog 實例:

$monolog = Log::getMonolog();