Laravel应用异常输出多日志通道问题排查问询
Laravel 10.13.5 日志异常问题
我负责的Laravel 10.13.5应用出现异常:同一条日志语句同时输出带有local和production环境标识的日志,日志示例如下:
[2024-02-21 13:05:47] local.INFO: UserDao.getByMatricule C182697 on 10.48.86.7 [2024-02-21 13:05:47] local.INFO: UserDao.getByMatricule C182697 on 10.48.86.7 [2024-02-21 13:05:47] local.INFO: UserDao.getByMatricule C182697 on 10.48.86.7 [2024-02-21 13:05:47] local.INFO: UserDao.getByMatricule C182697 on 10.48.86.7 [2024-02-21 13:05:47] production.INFO: UserDao.getByMatricule C182697 on 10.48.86.7 [2024-02-21 13:05:47] production.INFO: UserDao.getByMatricule C182697 on 10.48.86.7
日志调用代码:
Log::info('UserDao.getByMatricule ' . $matricule . ' on ' . $ip);
可以看到日志的环境标识在记录过程中从local切换到production,但config/logging.php中并没有配置名为local或production的日志通道。
应用.env配置:
APP_NAME=Laravel APP_ENV=local APP_DEBUG=false APP_URL=http://localhost LOG_CHANNEL=stack LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug
额外信息
- 存在生产和测试两台服务器,代码完全一致,仅数据库凭据不同;
.env其余配置(含APP_ENV、APP_KEY)完全相同 config/app.php和config/logging.php在两台服务器上一致,其中config/app.php里的配置为'env' => env('APP_ENV', 'production')- 应用已上线多年,该问题仅偶尔出现(55.7万行日志中仅出现70次)
- 两台服务器均位于反向代理后
- 用户反馈看到无权限内容,怀疑存在环境不匹配问题
问题
- 当前配置下,Laravel为何会输出带有两种不同环境标识的日志?
- 这些
local和production标识是如何产生的?
附config/logging.php配置:
<?php use Monolog\Handler\NullHandler; use Monolog\Handler\StreamHandler; use Monolog\Handler\SyslogUdpHandler; use Monolog\Processor\PsrLogMessageProcessor; return [ /* |-------------------------------------------------------------------------- | 默认日志通道 |-------------------------------------------------------------------------- | | 该选项定义写入日志时使用的默认日志通道,此处指定的名称必须与 | 下方"channels"配置数组中定义的通道名称匹配。 | */ 'default' => env('LOG_CHANNEL', 'stack'), /* |-------------------------------------------------------------------------- | 弃用日志通道 |-------------------------------------------------------------------------- | | 该选项控制用于记录PHP和库特性弃用警告的日志通道,帮助你 | 为依赖项的即将到来的大版本更新做好准备。 | */ 'deprecations' => [ 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 'trace' => false, ], /* |-------------------------------------------------------------------------- | 日志通道 |-------------------------------------------------------------------------- | | 你可以在此配置应用的日志通道。Laravel默认使用Monolog PHP日志库, | 这让你可以使用各种强大的日志处理器/格式化器。 | | 可用驱动:"single", "daily", "slack", "syslog", | "errorlog", "monolog", | "custom", "stack" | */ 'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => ['single'], 'ignore_exceptions' => false, ], 'single' => [ 'driver' => 'single', 'path' => storage_path('logs/laravel.log'), 'level' => env('LOG_LEVEL', 'debug'), 'replace_placeholders' => true, ], 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => env('LOG_LEVEL', 'debug'), 'days' => 14, 'replace_placeholders' => true, ], 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel Log', 'emoji' => ':boom:', 'level' => env('LOG_LEVEL', 'critical'), 'replace_placeholders' => true, ], 'papertrail' => [ 'driver' => 'monolog', 'level' => env('LOG_LEVEL', 'debug'), 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), 'handler_with' => [ 'host' => env('PAPERTRAIL_URL'), 'port' => env('PAPERTRAIL_PORT'), 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), ], 'processors' => [PsrLogMessageProcessor::class], ], 'stderr' => [ 'driver' => 'monolog', 'level' => env('LOG_LEVEL', 'debug'), 'handler' => StreamHandler::class, 'formatter' => env('LOG_STDERR_FORMATTER'), 'with' => [ 'stream' => 'php://stderr', ], 'processors' => [PsrLogMessageProcessor::class], ], 'syslog' => [ 'driver' => 'syslog', 'level' => env('LOG_LEVEL', 'debug'), 'facility' => LOG_USER, 'replace_placeholders' => true, ], 'errorlog' => [ 'driver' => 'errorlog', 'level' => env('LOG_LEVEL', 'debug'), 'replace_placeholders' => true, ], 'null' => [ 'driver' => 'monolog', 'handler' => NullHandler::class, ], 'emergency' => [ 'path' => storage_path('logs/laravel.log'), ], ], ];
解答
问题1:为何会输出带有两种不同环境标识的日志?
这种异常大概率是PHP-FPM(或其他进程管理器)的进程环境变量污染导致的:
- 两台服务器的
.env中APP_ENV都是local,但如果进程管理器的子进程在重启、回收时没有正确清除环境变量,可能会有个别子进程继承了旧的(甚至是跨服务器的)APP_ENV=production环境变量。 - 当请求被分配到这个异常进程时,Laravel会基于错误的
APP_ENV值初始化日志组件,导致日志标记为production;正常进程则使用正确的local环境,从而出现同一批次请求同时输出两种环境标识日志的情况。 - 反向代理/负载均衡配置错误导致同一请求被转发到两台服务器,也可能出现日志混合,但结合“仅偶尔出现”的特征,进程环境变量污染的可能性更高。
问题2:这些local和production标识是如何产生的?
你看到的local/production并不是日志通道名称,而是Laravel默认日志格式化器自动添加的环境标识:
- Laravel的默认日志格式会将
APP_ENV的值作为日志前缀的一部分(比如local.INFO里的local就是当前进程的APP_ENV值)。 - 你的
config/logging.php中实际使用的是stack→single通道,只是因为个别进程的APP_ENV被污染为production,导致日志前缀显示了错误的环境标识,看起来像是输出到了不同通道。
内容的提问来源于stack exchange,提问作者madgangmixers
相关产品推荐
相关产品推荐

