日志配置详解
日志系统的全部配置集中在 config/log.php。本篇给出完整配置项说明、内置 File 驱动的参数与存储规则,以及自定义日志驱动的扩展方式。
默认配置全览
框架自带的 config/log.php:
use Viswoole\Log\Drives\File;
return [
// 默认通道
'default' => 'file',
// 按日志级别指定写入通道,例如:['error' => 'email']
'type_channel' => [],
// 是否跟踪日志来源
'trace_source' => true,
// 是否同时将日志输出到控制台(只建议在开发环境中使用)
'console' => false,
// 日志驱动通道,可自行实现日志驱动:需继承 \Viswoole\Log\Drive 类
// 或实现 \Viswoole\Log\Contract\DriveInterface 接口
'channels' => [
'file' => File::class,
],
];配置项总表
| 配置键 | 类型 | 源码默认值 | 说明 |
|---|---|---|---|
| default | string | 首个通道名 | 默认通道名称,内部按小写索引 |
| type_channel | array | [] | 级别 → 通道映射,键为级别名,值为通道名或通道名数组;引用不存在的通道启动时抛 LogException |
| trace_source | bool | false | 是否记录调用来源(文件:行号);框架默认配置中显式设为 true |
| console | bool | true | 是否同步输出到控制台;框架默认配置中显式设为 false |
| channels | array | ['default' => File 实例] | 通道列表,键为通道名,值为驱动定义(三种形式见下) |
默认值差异
「源码默认值」指完全未提供该配置项时 LogManager 的兜底行为;框架自带的 config/log.php 覆盖了 trace_source 与 console 两项。通道列表完全未配置时,框架会注册一个名为 default 的 File 通道。
通道定义
channels 中每个通道支持三种形式:
use App\Log\ElasticsearchDrive;
use Viswoole\Log\Drives\File;
'channels' => [
// 形式一:驱动类名(容器无参实例化)
'file' => File::class,
// 形式二:配置数组,options 为驱动构造参数
'error' => [
'driver' => File::class,
'options' => [
'log_dir' => BASE_PATH . '/runtime/error_logs',
'storageDays' => 90,
],
],
// 形式三:驱动实例
'es' => new ElasticsearchDrive(['hosts' => ['http://127.0.0.1:9200']]),
],驱动类不存在、options 格式错误或未实现 DriveInterface 时抛出 LogException。通道名内部统一转小写。
File 驱动
内置驱动 Viswoole\Log\Drives\File 将日志写入本地文件,按「日期 / 级别」两级目录组织,支持按大小切割与每日自动清理。
构造参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| storageDays | int | 7 | 日志保留天数,超期日期目录被自动清理 |
| maxFiles | int | 30 | 单个级别下最大文件数量,超出后删除最早文件 |
| fileSize | int | 10485760 | 单文件最大字节数(10MB),超出自动切割 |
| dateFormat | string | c | 时间戳格式(date() 格式字符) |
| logFormat | string | 见下文 | 文本格式规则,json 为 false 时生效 |
| json | bool | true | 是否以 JSON 格式存储 |
| json_flags | int | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON 编码标志位 |
| log_dir | string | BASE_PATH.'/runtime/logs' | 日志根目录 |
默认文本格式为 [%timestamp][%level]: %message %context in %source。
存储结构
runtime/logs/
├── 20260911/
│ ├── info/
│ │ ├── info_0.log
│ │ └── info_1.log # 超过 fileSize 后切割出的新文件
│ ├── error/
│ │ └── error_0.log
│ └── sql/
└── 20260912/
└── ...写入与清理规则:
- 切割:单个文件达到
fileSize后,新日志写入编号 +1 的新文件(info_1.log→info_2.log) - 数量上限:单级别文件数超过
maxFiles时删除最早的文件 - 自动清理:构造时注册 Swoole 定时器,每日凌晨清理目录名超过
storageDays的日期目录;日期目录名必须是 8 位Ymd数字格式,避免误删其他目录
JSON 与文本格式
json: true(默认)时每条日志一行 JSON,字段固定为 timestamp、level、message、context、source:
{
"timestamp": "2026-01-01T12:00:00+08:00",
"level": "info",
"message": "用户登录",
"context": { "uid": 1 },
"source": "/app/Controller/AuthController.php:25"
}json: false 时按 logFormat 渲染,支持占位符:
| 占位符 | 说明 |
|---|---|
%timestamp | 按 dateFormat 格式化的时间 |
%level | 日志级别 |
%message | 日志消息 |
%context | 上下文数据(JSON 编码,空时显示 {}) |
%source | 调用来源 |
'options' => [
'json' => false,
'logFormat' => '%timestamp | [%level] %message %context in %source',
],格式规则兼容 sprintf
logFormat 中不含 %占位符 时,规则将按 vsprintf 语义处理,日志字段按 timestamp、level、message、context、source 顺序填充。
自定义日志驱动
继承 Drive 基类(推荐)
Viswoole\Log\Drive 已实现级别快捷方法、协程聚合缓存(record)与直写(write)逻辑,子类只需实现 save() 定义持久化策略,协程结束时由 Recorder 自动批量调用:
namespace App\Log;
use Viswoole\Log\Drive;
class DatabaseDrive extends Drive
{
public function __construct(protected string $table = 'system_logs')
{
}
/**
* 批量持久化日志(协程结束时自动调用)
*
* @param array<int, array{
* timestamp: int, level: string, message: string,
* context: array, source: string
* }> $logRecords
*/
public function save(array $logRecords): void
{
foreach ($logRecords as $record) {
// 写入数据库 / 推送到外部服务等
}
}
}驱动内的协程安全
基类把聚合缓存放在每个协程独立的 Recorder(存于协程上下文)中,自定义 save() 无需关心协程隔离,只需专注批量持久化本身。
接口契约
不继承基类时,需实现 Viswoole\Log\Contract\DriveInterface 的全部方法,它由两部分组成:
CollectorInterface(收集器接口):error/warning/info/debug/alert/sql/task七个级别方法与mixed($level, $message, $context)- 驱动扩展:
record()(协程缓存写入)、write()(直写)、save(array $logRecords)(批量持久化)、getRecord()/clearRecord()(协程缓存读取与清理)
因此自行实现时需同时处理「级别分发 + 协程聚合 + 持久化」三层逻辑,没有特殊理由建议直接继承 Drive。
注册自定义通道
// 方式一:config/log.php(推荐)
'channels' => [
'database' => [
'driver' => \App\Log\DatabaseDrive::class,
'options' => ['table' => 'app_logs'],
],
],
// 方式二:服务启动前动态注册
Log::addChannel('database', \App\Log\DatabaseDrive::class);结合 type_channel 可把指定级别导入自定义通道,实现错误告警、审计入库等策略,见 级别与通道。
环境变量集成
推荐通过环境变量区分环境差异,读取方式见 环境变量:
use Viswoole\Log\Drives\File;
return [
'default' => env('LOG_CHANNEL', 'file'),
'console' => env('APP_DEBUG', false),
'channels' => [
'file' => [
'driver' => File::class,
'options' => [
'storageDays' => (int)env('LOG_STORAGE_DAYS', 7),
'log_dir' => env('LOG_DIR', BASE_PATH . '/runtime/logs'),
],
],
],
];LOG_CHANNEL=file
LOG_STORAGE_DAYS=30
LOG_DIR=/var/log/viswoole