什么是日志
Laravel 日志系统以**通道(Channel)**为核心概念。
通道指的是一组定义了日志写入目标与方式的配置单元,可以组合文件、Slack、syslog 等各种输出目的地。
底层使用 Monolog 库,可以充分利用其丰富的 handler 与 formatter。
默认使用 stack 通道。stack 是把多个通道组合在一起的父通道。
日志配置集中在 config/logging.php 中。可通过环境变量 LOG_CHANNEL 切换默认通道。
// config/logging.php
'default' => env ( 'LOG_CHANNEL' , 'stack' ),
可用的通道驱动
驱动 说明 single把所有日志写入单一文件 daily按日期拆分文件写入(自动轮转) slack通过 Slack Incoming Webhook 发送消息 stack组合多个通道的父通道 syslog写入系统 syslog errorlog写入 PHP 错误日志 monolog直接指定 Monolog 的 handler custom通过工厂类完全自定义通道
日志级别
Laravel 支持 RFC 5424 定义的 8 个日志级别,按严重性从高到低排列:
级别 用途示例 emergency系统整体不可用,需立即处理 alert必须由人立即介入的状态(如数据库断连) critical主要功能停摆的重大故障 error运行时错误,需要处理,但通常不必即时 warning潜在问题,如使用了已弃用 API、遇到意外数据 notice正常运行,但值得关注的信息 info用户登录、订单确认等常规操作日志 debug开发时的详细调试信息
通道的 level 设置表示最低日志级别 。
例如 level 为 error 时,只会记录 error 及以上(critical、alert、emergency)。
基本用法
Log 门面
使用 Illuminate\Support\Facades\Log 门面按级别写入日志。
use Illuminate\Support\Facades\ Log ;
Log :: emergency ( '系统已停机。' );
Log :: alert ( '数据库连接已断开。' );
Log :: critical ( '支付服务无响应。' );
Log :: error ( '更新用户数据失败。' );
Log :: warning ( '调用了已弃用的方法。' );
Log :: notice ( '配置文件已重载。' );
Log :: info ( '用户已登录。' );
Log :: debug ( '查询执行耗时:42ms' );
在控制器中的示例:
<? php
namespace App\Http\Controllers ;
use App\Models\ User ;
use Illuminate\Support\Facades\ Log ;
use Illuminate\View\ View ;
class UserController extends Controller
{
public function show ( string $id ) : View
{
Log :: info ( '显示用户资料。' , [ 'user_id' => $id ]);
return view ( 'user.profile' , [
'user' => User :: findOrFail ( $id ),
]);
}
}
log() 辅助函数
使用 log() 辅助函数可以无需 import Log 门面直接写。
log ( '来自 helper 的日志。' );
// 也可以指定级别和上下文
log ( '已创建用户。' , 'info' , [ 'user_id' => $user -> id ]);
附加上下文信息
传入上下文(数组)可与消息一起记录相关信息。
Log :: info ( '登录失败。' , [
'user_id' => $user -> id ,
'ip' => $request -> ip (),
'reason' => '密码不匹配' ,
]);
withContext() — 为通道后续所有日志附加公共上下文
若希望对特定通道之后的所有日志附加公共信息,可使用 withContext()。
适合像请求 ID 这样希望出现在所有日志中的信息。
Log :: withContext ([ 'request-id' => ( string ) Str :: uuid ()]);
// 之后所有日志都会自动包含 request-id
Log :: info ( '开始处理。' );
Log :: error ( '发生错误。' );
shareContext() — 对所有通道附加公共上下文
withContext() 只对目标通道生效,而 shareContext() 会作用于所有通道。
Log :: shareContext ([ 'app-version' => config ( 'app.version' )]);
通道配置
stack 通道 — 同时写入多个通道
stack 通道让你一次调用同时写入多个通道。
// config/logging.php
'channels' => [
'stack' => [
'driver' => 'stack' ,
'channels' => [ 'daily' , 'slack' ],
],
'daily' => [
'driver' => 'daily' ,
'path' => storage_path ( 'logs/laravel.log' ),
'level' => env ( 'LOG_LEVEL' , 'debug' ),
'days' => 14 ,
],
'slack' => [
'driver' => 'slack' ,
'url' => env ( 'LOG_SLACK_WEBHOOK_URL' ),
'username' => env ( 'LOG_SLACK_USERNAME' , 'Laravel Log' ),
'emoji' => env ( 'LOG_SLACK_EMOJI' , ':boom:' ),
'level' => 'critical' ,
],
],
以上配置将 debug 以上的日志写入 daily(文件),只有 critical 以上的日志才会发送到 slack。
在生产环境,建议将 slack 通道级别设为 error 或 critical。
若将琐碎日志推送到 Slack,会产生大量通知,重要告警反而容易被淹没。
daily 通道 — 日志轮转
daily 通道按日期分文件保存,并自动清理旧文件。
'daily' => [
'driver' => 'daily' ,
'path' => storage_path ( 'logs/laravel.log' ),
'level' => env ( 'LOG_LEVEL' , 'debug' ),
'days' => env ( 'LOG_DAILY_DAYS' , 14 ), // 保留 14 天
],
days 越小旧日志越快被删除。
为在生产环境排查故障,请保留足够的保留期。
向 Slack 发送错误通知
获取 Slack 的 Incoming Webhook URL 并配置到 .env 中。
LOG_SLACK_WEBHOOK_URL =https://hooks.slack.com/services/xxx/yyy/zzz
// config/logging.php
'slack' => [
'driver' => 'slack' ,
'url' => env ( 'LOG_SLACK_WEBHOOK_URL' ),
'username' => 'Laravel Error Bot' ,
'emoji' => ':fire:' ,
'level' => 'error' ,
],
在 stack 通道中加入 slack 并设置 LOG_CHANNEL=stack,发生错误时会自动通知。
写入特定通道
通过 Log::channel() 显式指定目标通道。
// 只写入 slack
Log :: channel ( 'slack' ) -> error ( '支付服务无响应。' );
// 同时写入多个通道
Log :: stack ([ 'daily' , 'slack' ]) -> critical ( '数据库连接失败。' );
按需通道
使用 Log::build() 可以在不修改配置文件的情况下即时构建自定义通道。
适合测试或临时的输出目的。
use Illuminate\Support\Facades\ Log ;
$channel = Log :: build ([
'driver' => 'single' ,
'path' => storage_path ( 'logs/import-' . now () -> format ( 'Ymd' ) . '.log' ),
]);
Log :: stack ([ $channel ]) -> info ( '开始导入 CSV。' );
实用场景
通过中间件附加请求 ID
给所有日志附加同一个请求 ID,能大幅提升按请求追踪日志的能力。
创建中间件
php artisan make:middleware AssignRequestId
实现 handle() 方法
<? php
namespace App\Http\Middleware ;
use Closure ;
use Illuminate\Http\ Request ;
use Illuminate\Support\Facades\ Log ;
use Illuminate\Support\ Str ;
use Symfony\Component\HttpFoundation\ Response ;
class AssignRequestId
{
public function handle ( Request $request , Closure $next ) : Response
{
$requestId = ( string ) Str :: uuid ();
Log :: withContext ([ 'request-id' => $requestId ]);
$response = $next ( $request );
$response -> headers -> set ( 'X-Request-Id' , $requestId );
return $response ;
}
}
注册中间件
在 bootstrap/app.php 中作为全局中间件注册。 -> withMiddleware ( function ( Middleware $middleware ) {
$middleware -> append ( \App\Http\Middleware\ AssignRequestId :: class );
})
配置好后,所有日志都会自动附带 request-id。
[2026-03-01 12:00:00] local.INFO: 用户已登录。 {"request-id":"550e8400-...","user_id":1}
[2026-03-01 12:00:00] local.INFO: 显示仪表盘。 {"request-id":"550e8400-..."}
记录弃用警告
可以将 PHP 或 Laravel 弃用功能的调用记录到日志中。
// config/logging.php
'deprecations' => [
'channel' => env ( 'LOG_DEPRECATIONS_CHANNEL' , 'null' ),
'trace' => env ( 'LOG_DEPRECATIONS_TRACE' , false ),
],
在 .env 中指定通道:
LOG_DEPRECATIONS_CHANNEL =daily
Laravel Pail — 实时日志监视
Laravel Pail 是可以在终端实时查看应用日志的开发工具。
运行 Pail 需要 PHP 的 PCNTL 扩展。
composer require --dev laravel/pail
基本用法
# 流式查看日志
php artisan pail
# 详细展示(不省略)
php artisan pail -v
# 同时展示堆栈
php artisan pail -vv
日志过滤
# 按关键字过滤
php artisan pail --filter= "QueryException"
# 只按消息过滤
php artisan pail --message= "登录"
# 按级别过滤
php artisan pail --level=error
# 只显示特定用户的日志
php artisan pail --user=1
级别 使用场景 emergency系统整体停机等致命故障 alert必须由人立即介入的状态 critical主要功能停摆的重大故障 error意料之外的运行时错误,需要处理 warning使用已弃用功能、遇到异常数据等需要关注的状态 notice正常但值得记录的重要操作 info用户操作、业务事件的记录 debug开发期间的详细调试信息(生产环境通常不需要)
开发环境 :使用 single 或 daily 写文件
生产环境 :使用 stack 组合 daily(文件保存)和 slack(错误通知)
特定处理的日志 :使用 Log::build() 创建按需通道写入独立文件
实时监视 :使用 php artisan pail 从终端查看
debug 日志中可能包含敏感信息,生产环境建议使用 LOG_LEVEL=error 或更高。
日志文件请定期轮转,避免占满磁盘(使用 daily 通道的 days 设置)。
向 Slack 等外部服务发送通知时注意速率限制,只推送严重错误。