Log::info() 无反应因三原因:APP_LOG_LEVEL过低过滤info、storage/logs目录权限不足、config/logging.php中stack通道配置异常;支付日志应新增payment通道而非修改调用方式。

默认情况下,Log::info() 等调用会写入 storage/logs/laravel.log,但前提是 config/logging.php 中的 stack 通道配置正常、日志目录可写、且未被环境变量禁用。
为什么 Log::info() 没反应?检查这三处
常见现象:代码里写了 Log::info('test'),但 storage/logs/ 下没生成或没更新 laravel.log。
-
APP_LOG_LEVEL环境变量设得太低(如error),而info级别被过滤 —— 检查.env是否有该变量,或删掉它让框架用默认debug -
storage/logs/目录权限不对(尤其在 Linux 上),PHP 进程无法写入 —— 执行chmod -R 755 storage/或更稳妥地用chown -R www-data:www-data storage/ -
config/logging.php被意外修改,导致stack通道的channels数组为空,或底层single驱动的path指向了不存在的路径
想把支付日志单独存到 payment.log?配 channel 就行
不要改 Log::info() 的调用方式,而是新增一个日志通道。这是 Laravel 推荐的隔离策略,避免混杂和轮转冲突。
在 config/logging.php 的 'channels' => [...] 数组里加一段:
'payment' => [
'driver' => 'daily',
'path' => storage_path('logs/payment.log'),
'level' => 'debug',
'days' => 14,
],
之后在代码中直接调用:Log::channel('payment')->info('order_id=12345');
- 每个
channel是独立实例,level和文件路径不共享 - 用
daily驱动会自动按天切分,比如payment-2026-04-19.log,比single更适合长期运行的服务 - 如果该 channel 同时要推送到 Sentry,加一行
'tap' => [App\Logging\SentryTap::class]即可
全局记录 HTTP 请求日志?中间件里别直接 file_put_contents
用 file_put_contents('request.log', ...) 写死路径,既不兼容多 worker 场景,也绕过了 Laravel 日志系统的所有配置(如轮转、级别控制、formatter)。
- 正确做法是:在自定义中间件中调用
Log::channel('http')->debug(...),并提前在config/logging.php配好httpchannel - 注意请求对象不能直接字符串化(
$request是对象),要用$request->fullUrl()、$request->method()、$request->ip()等方法提取字段 - 别在中间件里记录
$request->getContent(),POST 大体请求会阻塞流、影响后续中间件读取
日志内容乱码或 JSON 字段被截断?看 formatter 配置
Laravel 默认用 LineFormatter,输出纯文本;如果需要结构化 JSON(比如对接 ELK),得改 channel 的 tap 或自定义 driver。
- 最简方案:在 channel 配置里加
'formatter' => \Monolog\Formatter\JsonFormatter::class(仅限支持 formatter 的驱动,如single、daily) - 但要注意:JSON 格式下
context参数会被扁平化,比如Log::info('msg', ['user' => ['id'=>123]])会变成"user.id":123 - 如果用了
stack通道,formatter 必须在每个子 channel 里单独配,stack 本身不接管格式化
真正麻烦的不是怎么写日志,而是怎么让不同模块的日志不互相污染、不抢锁、不撑爆磁盘 —— channel 隔离 + daily 轮转 + level 控制,这三者缺一不可。别省略 days 配置,否则 daily 通道不会自动清理旧文件。


















