日志使用方法
基本记录
使用门面调用
php
use Viswoole\Log\Facade\Log;
// 记录信息日志
Log::info('用户注册成功', ['user_id' => 100, 'email' => 'test@example.com']);
// 记录错误日志
Log::error('支付失败', ['order_id' => 'ORD001', 'reason' => '余额不足']);
// 记录调试日志
Log::debug('API请求', ['url' => '/api/users', 'method' => 'GET']);
// 记录警告日志
Log::warning('内存使用率过高', ['usage' => '85%']);支持的快捷方法
php
// 框架提供的所有日志级别快捷方法
Log::alert($message, $context); // 必须立即采取行动
Log::error($message, $context); // 运行时错误
Log::warning($message, $context); // 警告异常情况
Log::info($message, $context); // 一般信息
Log::debug($message, $context); // 调试详细信息
Log::sql($message, $context); // SQL 执行记录
Log::task($message, $context); // 异步任务记录
// emergency、critical、notice 等非内置级别请使用 mixed 方法:
Log::mixed('emergency', $message, $context);
Log::mixed('critical', $message, $context);
Log::mixed('notice', $message, $context);自定义级别
php
// 记录自定义级别的日志
Log::mixed('custom', '自定义级别消息', ['key' => 'value']);上下文数据
传递上下文
php
// 传递关联数据
Log::info('订单创建', [
'order_id' => 'ORD-20240101-001',
'amount' => 299.00,
'user_id' => 1001,
'ip' => request()->getRealIp()
]);
// 日志输出示例:
// {"timestamp":"2024-01-01T12:00:00+08:00","level":"info","message":"订单创建","context":{"order_id":"ORD-20240101-001","amount":299,"user_id":1001,"ip":"192.168.1.100"},"source":"Controller.php:45"}对象消息支持
php
// 消息参数支持 Stringable 接口的对象
class LogMessage implements Stringable
{
public function __toString(): string
{
return '自定义格式化消息';
}
}
Log::info(new LogMessage(), ['data' => '...']);写入模式
record() - 协程缓存模式(推荐)
默认模式下,日志会缓存在当前协程中,协程结束时自动批量写入:
php
// 这些日志不会立即写入文件
Log::info('步骤1完成');
Log::debug('中间变量', ['x' => 10]);
Log::info('步骤2完成');
// 协程结束时,以上3条日志一次性批量写入这是框架在 Swoole 协程环境下的推荐模式,能有效减少 I/O 操作次数。
write() - 直接写入模式
绕过协程缓存,立即将日志写入存储:
php
// 立即写入,不经过协程缓存
Log::write('error', '严重错误需要立即持久化', ['critical' => true]);
// 注意:write() 与 error() 的区别
// - write() 绕过协程缓存,立即落盘,适合需要即时持久化的关键日志
// - error() 在协程环境下会缓存到协程结束,再批量写入
Log::error('严重错误...', [...]); // 协程环境下会缓存手动管理缓存
php
// 获取当前协程已缓存的日志(尚未写入)
$records = Log::getRecord();
// 清除当前协程缓存的日志(不写入)
Log::clearRecord();
// 手动触发批量保存(通常无需手动调用)
Log::save($records);指定通道写入
切换通道
php
// 向指定通道写入日志
Log::channel('file')->info('只写文件通道');
// 判断通道是否存在
if (Log::hasChannel('file')) {
Log::channel('file')->debug('调试信息');
}动态添加通道
php
// 运行时添加新通道(需在服务启动前)
Log::addChannel('custom', CustomDriver::class);
// 通过数组配置添加
Log::addChannel('custom', [
'driver' => \Viswoole\Log\Drives\File::class,
'options' => [
'log_dir' => BASE_PATH . '/runtime/custom_logs',
'json' => false,
]
]);实际应用示例
请求日志中间件
php
class RequestLogMiddleware implements MiddlewareInterface
{
public function process(Closure $handler): mixed
{
$start = microtime(true);
$response = $handler();
$duration = round((microtime(true) - $start) * 1000, 2);
Log::info('HTTP请求', [
'method' => request()->getMethod(),
'uri' => request()->getRequestUri(),
'status' => $response->getStatusCode(),
'duration' => "{$duration}ms",
'ip' => request()->getRealIp(),
]);
return $response;
}
}异常日志记录
php
try {
// 业务代码...
} catch (\Throwable $e) {
Log::error('业务异常', [
'exception' => get_class($e),
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}SQL 日志记录
php
class DatabaseService
{
public function query(string $sql, array $params = []): array
{
$start = microtime(true);
try {
$result = $this->pdo->query($sql);
$duration = round((microtime(true) - $start) * 1000, 2);
Log::sql('查询执行成功', [
'sql' => $sql,
'params' => $params,
'duration' => "{$duration}ms",
'rows' => count($result),
]);
return $result;
} catch (\PDOException $e) {
Log::error('数据库查询失败', [
'sql' => $sql,
'error' => $e->getMessage(),
]);
throw $e;
}
}
}