最直接方式是修改 config/logging.php 中 'single' 通道的 'path' 为 storage_path('logs/custom/app.log');若需按日分割,则改用 'daily' 驱动并配置 path 和 days;动态切换需用 log::swap() 或 log::channel(),但要注意权限、目录存在性及运行上下文一致性。

修改 config/logging.php 中的 path 配置项
默认 Laravel 把日志写到 storage/logs/laravel.log,想换路径,最直接的方式是改日志通道的 path。Laravel 的 stack 默认用 single 通道,而 single 驱动支持 path 参数。
打开 config/logging.php,找到 'single' => [...] 这一段,在里面加或改:
'path' => storage_path('logs/custom/app.log'),
注意:storage_path() 返回的是 storage/ 目录绝对路径,别手写相对路径,否则可能写到错地方。
- 路径目录必须存在且 Web 服务器用户(如 www-data、nginx)有写权限,否则日志静默失败
- 不要用
./logs/...或../logs/...——single驱动不解析相对路径,会直接拼进storage_path()后面,结果变成storage/./logs/...这种非法路径 - 如果路径含日期变量(比如按天分文件),
single不支持,得切到daily驱动并配path+days
用 daily 驱动实现按日期分割 + 自定义路径
想保留每天一个文件(如 laravel-2024-06-15.log)又指定位置,不能只改 single,得换驱动。Laravel 的 daily 驱动同样支持 path,还多一个 days 控制保留天数。
在 config/logging.php 中新增或替换一个通道:
'custom_daily' => [
'driver' => 'daily',
'path' => storage_path('logs/custom/daily/app.log'),
'level' => 'debug',
'days' => 7,
],
然后在 'default' 或 'stack.channels' 中引用它,比如把 'stack' 的 channels 改成 ['custom_daily']。
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
-
daily驱动会自动在path文件名后追加日期(如app.log→app-2024-06-15.log),所以path最后必须是.log文件,不能是目录 - 如果设了
path为storage_path('logs/custom')(没带文件名),会报InvalidArgumentException: Log file path must be a file -
days是软限制:Laravel 只在新日志轮转时清理旧文件,不是定时任务,所以如果应用长期不写日志,旧文件不会被删
运行时动态切换日志路径(不推荐但可行)
极少数场景需要按请求、环境或租户动态变路径,比如多租户 SaaS 每个客户独立日志目录。这时不能靠配置文件静态定义,得在运行时干预日志实例。
Laravel 日志门面底层是 Logger 实例,可通过 Log::swap() 替换。例如在中间件或服务提供者里:
use Illuminate\Support\Facades\Log;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
$customPath = storage_path("logs/tenants/{$tenantId}/app.log");
$handler = new StreamHandler($customPath, Logger::DEBUG);
$logger = new Logger('custom');
$logger->pushHandler($handler);
Log::swap($logger);
但要注意:
- 每次请求都这么换,性能损耗明显;更稳妥的做法是提前注册多个通道,用
Log::channel('tenant_'.$id)切换 - Monolog 的
StreamHandler不会自动创建父目录,$customPath的目录(如logs/tenants/123)得提前mkdir -p并设好权限 - 这种写法绕过了 Laravel 日志配置体系,
LOG_LEVEL环境变量、tap钩子等可能失效
权限与部署时容易漏掉的检查点
改完路径跑不通,90% 是权限问题,尤其上线后。
- 确保整个路径层级(包括
storage/logs/custom)对 Web 用户可写:chown -R www-data:www-data storage/logs/custom - 如果用 Supervisor 管理队列或 Horizon,它的日志也走 Laravel 日志系统,但运行用户可能是
ubuntu或deploy,需单独赋权 - Docker 环境下,宿主机映射的
storage目录 UID/GID 要和容器内 Web 用户一致,否则touch: cannot touch '...': Permission denied - Git 忽略了
storage/logs,但自定义路径如storage/logs/custom如果没加进.gitignore,可能误提交空目录或权限信息
路径本身很简单,难的是让所有运行上下文(Web、CLI、队列、Docker)都写得进去,而且不因部署方式不同就崩掉。










