一个功能强大的 Webman 框架请求链路追踪插件,提供完整的调试和监控解决方案。
jsont_success(), jsont_error() 等方法trace_info(), trace_error() 等日志函数composer require openb8/webman-trace
安装完成即可使用! 插件会自动:
config/plugin/openb8/webman-trace/php start.php restart
立即享受完整的追踪功能!
启动服务后,控制台会显示类似这样的美观输出:
🚀 新请求 [trace-abc123] ┃ 时间: 2024-01-30 10:00:00 ┃ 方法: POST ┃ 路径: /api/user/login ┃ 来源IP: 127.0.0.1 ┃ 请求参数: ┃ { ┃ "username": "admin", ┃ "password": "******" ┃ } ┌─────────────────────────────────────────────────────────────┐ │ 时间: 2024-01-30 10:00:00 │ Trace ID: trace-abc123 │ 状态码: ✅ 200 │ 请求方式: POST │ 接口: /api/user/login │ 耗时: 25.67ms │ 响应数据: │ { │ "code": 0, │ "msg": "登录成功", │ "data": {...} │ } └─────────────────────────────────────────────────────────────┘
访问 http://127.0.0.1:8787/trace 即可使用:
配置文件:config/plugin/openb8/webman-trace/app.php
return [
'enable' => true,
// 控制台美化输出
'console_output' => [
'enable' => true,
'verbose' => true, // 显示详细信息
'beautiful' => true, // 美化显示
'levels' => ['request', 'response', 'exception', 'slow_query'],
],
// Web查询界面
'web_interface' => [
'enable' => true,
'path_prefix' => '/trace',
'auth_required' => false, // 开发环境无需认证
],
// 请求体和响应体记录
'log_body' => [
'request' => true, // 记录请求参数
'response' => true, // 记录响应数据
'max_length' => 1024, // 最大长度限制
],
// 404追踪
'handle_404' => [
'enable' => true, // 启用404追踪
'custom_response' => false, // 仅记录,不覆盖原有404页面
],
];
return [
'enable' => true,
// 关闭控制台输出(减少性能影响)
'console_output' => [
'enable' => false,
],
// Web界面需要认证
'web_interface' => [
'enable' => true,
'auth_required' => true,
'access_password' => 'your-secure-password',
],
// 减少日志体积
'log_body' => [
'request' => false,
'response' => false,
],
// 仅记录关键信息
'log_levels' => [
'request' => 'info',
'response' => 'info',
'sql' => 'warning', // 只记录慢查询
'exception' => 'error',
],
];
return [
// 基础开关
'enable' => true,
'log_sql' => true,
'log_exception' => true,
'log_request' => true,
'debug_only' => false,
// 控制台输出
'console_output' => [
'enable' => true,
'levels' => ['request', 'response', 'exception', 'slow_query'],
'verbose' => true, // 详细模式开关
'beautiful' => true, // 美化输出开关
],
// Web查询界面
'web_interface' => [
'enable' => true,
'path_prefix' => '/trace',
'auth_required' => false,
'access_password' => 'trace123',
'per_page' => 20,
],
// 404处理
'handle_404' => [
'enable' => true, // 启用404追踪
'custom_response' => false, // 是否自定义404响应
'response_body' => '404 Not Found', // 自定义404页面内容
],
// 日志配置
'log_file' => 'runtime/logs/trace.log',
'trace_id_key' => 'X-Trace-Id',
'trace_id_generator' => \OpenB8\WebmanTrace\Generator\UuidGenerator::class,
// 过滤配置
'ignore_paths' => [
'/favicon.ico',
'/robots.txt',
'/health',
],
// 性能配置
'slow_query_threshold' => 1000, // 慢查询阈值(毫秒)
'log_body' => [
'request' => true,
'response' => true,
'max_length' => 1024,
],
// 日志级别
'log_levels' => [
'request' => 'info',
'response' => 'info',
'sql' => 'debug',
'exception' => 'error',
'slow_query' => 'warning',
],
];
// 在任何地方获取当前请求的 Trace ID
$traceId = trace_id();
echo "当前 Trace ID: " . $traceId;
// 使用便捷的日志函数(自动包含 trace_id)
trace_info('用户登录成功', ['user_id' => 123]);
trace_error('数据库连接失败', ['error' => $exception->getMessage()]);
trace_debug('调试信息', ['data' => $debugData]);
trace_warning('磁盘空间不足', ['usage' => '90%']);
插件提供了四个便捷的 JSON 响应方法,自动包含 Trace ID:
// 自动为任何数据添加 trace_id
return jsont(['name' => '张三', 'age' => 25]);
// 输出: {"name": "张三", "age": 25, "trace_id": "abc123"}
return jsont($user, 200, ['Custom-Header' => 'value']);
return jsont_success($user, '获取用户信息成功');
// 输出: {
// "code": 0,
// "message": "获取用户信息成功",
// "data": {...},
// "trace_id": "abc123"
// }
return jsont_error('用户不存在', 1001, null, 404);
// 输出: {
// "code": 1001,
// "message": "用户不存在",
// "trace_id": "abc123"
// }
// HTTP状态码: 404
// 带错误详情
return jsont_error('验证失败', 1002, ['field' => 'email']);
return jsont_paginate($users, 100, 2, 10, '获取用户列表成功');
// 输出: {
// "code": 0,
// "message": "获取用户列表成功",
// "data": {
// "items": [...],
// "pagination": {
// "total": 100,
// "page": 2,
// "page_size": 10,
// "total_pages": 10,
// "has_next": true,
// "has_prev": true
// }
// },
// "trace_id": "abc123"
// }
<?php
class UserController
{
public function login($request)
{
// 记录开始处理
trace_info('开始处理用户登录', [
'ip' => $request->getRealIp(),
'user_agent' => $request->header('user-agent')
]);
try {
// 业务逻辑
$user = $this->authenticate($request);
// 记录成功
trace_info('用户登录成功', ['user_id' => $user->id]);
// 返回成功响应(自动包含 trace_id)
return jsont_success([
'user' => $user,
'token' => $this->generateToken($user)
], '登录成功');
} catch (\Exception $e) {
// 记录异常(异常会被自动追踪)
trace_error('用户登录失败', [
'error' => $e->getMessage(),
'code' => $e->getCode()
]);
// 返回错误响应
return jsont_error('登录失败: ' . $e->getMessage(), 1001, null, 401);
}
}
public function getUserList($request)
{
$page = max(1, (int)$request->get('page', 1));
$pageSize = min(100, max(1, (int)$request->get('page_size', 15)));
try {
$users = $this->userService->getUsers($page, $pageSize);
$total = $this->userService->getUserCount();
// 分页响应
return jsont_paginate($users, $total, $page, $pageSize);
} catch (\Exception $e) {
return jsont_error('获取用户列表失败', 2001);
}
}
}
插件生成标准的 JSON 格式日志,便于各种日志系统解析:
{
"trace_id": "trace-abc123456789",
"level": "INFO",
"type": "request",
"method": "POST",
"path": "/api/user/login",
"query": "remember=1",
"user_agent": "Mozilla/5.0...",
"ip": "127.0.0.1",
"body": "{\"username\":\"admin\",\"password\":\"******\"}",
"timestamp": "2024-01-30T10:00:00.123+08:00"
}
{
"trace_id": "trace-abc123456789",
"level": "INFO",
"type": "response",
"method": "POST",
"path": "/api/user/login",
"status": 200,
"duration": "25.67ms",
"body": "{\"code\":0,\"message\":\"登录成功\",\"data\":{...}}",
"timestamp": "2024-01-30T10:00:00.148+08:00"
}
{
"trace_id": "trace-abc123456789",
"level": "DEBUG",
"type": "sql",
"sql": "SELECT * FROM users WHERE email = ? AND status = ?",
"bindings": ["admin@example.com", 1],
"time": "12.34ms",
"timestamp": "2024-01-30T10:00:00.135+08:00"
}
{
"trace_id": "trace-abc123456789",
"level": "ERROR",
"type": "exception",
"class": "InvalidArgumentException",
"message": "用户名不能为空",
"file": "/var/www/app/controller/UserController.php",
"line": 45,
"trace": "Exception trace...",
"method": "POST",
"path": "/api/user/login",
"timestamp": "2024-01-30T10:00:00.140+08:00"
}
显示完整的请求参数和响应数据:
🚀 新请求 [trace-abc123] ┃ 时间: 2024-01-30 10:00:00 ┃ 方法: POST ┃ 路径: /api/user/login ┃ 来源IP: 127.0.0.1 ┃ 查询参数: remember=1 ┃ 请求参数: ┃ { ┃ "username": "admin", ┃ "password": "123456" ┃ } ┌─────────────────────────────────────────────────────────────┐ │ 时间: 2024-01-30 10:00:00 │ Trace ID: trace-abc123 │ 状态码: ✅ 200 │ 请求方式: POST │ 接口: /api/user/login │ 耗时: 25.67ms │ 响应数据: │ { │ "code": 0, │ "message": "登录成功", │ "data": { │ "user": {...}, │ "token": "..." │ } │ } └─────────────────────────────────────────────────────────────┘ 💥 异常发生 [trace-abc123] ┃ 时间: 2024-01-30 10:00:05 ┃ 类型: InvalidArgumentException ┃ 消息: 用户名不能为空 ┃ 位置: UserController.php:45 🔍 SQL查询 [trace-abc123] ┃ 时间: 2024-01-30 10:00:01 ┃ 耗时: 12.34ms ┃ SQL: SELECT * FROM users WHERE email = ? AND status = ? ┃ 参数: ["admin@example.com", 1]
只显示关键信息:
🚀 新请求 [trace-abc123] ┃ 时间: 2024-01-30 10:00:00 ┃ 方法: POST ┃ 路径: /api/user/login ┃ 来源IP: 127.0.0.1 ┌─────────────────────────────────────────────────────────────┐ │ 时间: 2024-01-30 10:00:00 │ Trace ID: trace-abc123 │ 状态码: ✅ 200 │ 请求方式: POST │ 接口: /api/user/login │ 耗时: 25.67ms └─────────────────────────────────────────────────────────────┘ 🔍 SQL查询 [trace-abc123] ┃ 时间: 2024-01-30 10:00:01 ┃ 耗时: 12.34ms ┃ SQL: SELECT * FROM users WHERE email = ? AND...
'web_interface' => [
'enable' => true,
'path_prefix' => '/trace',
'auth_required' => true, // 启用认证保护
'access_password' => 'trace123',
'per_page' => 20,
],
http://127.0.0.1:8787/trace
auth_required: false)use OpenB8\WebmanTrace\Generator\GeneratorInterface;
class CustomTraceGenerator implements GeneratorInterface
{
public function generate(): string
{
// 自定义生成逻辑
return 'custom_' . uniqid() . '_' . time();
}
}
// 在配置中指定
'trace_id_generator' => \App\Trace\CustomTraceGenerator::class,
插件支持从请求头中读取外部系统的 Trace ID:
# 传入外部 Trace ID
curl -H "X-Trace-Id: external-system-trace-123" \
http://127.0.0.1:8787/api/users
'ignore_paths' => [
'/favicon.ico',
'/robots.txt',
'/health',
'/metrics',
'*.css',
'*.js',
'/static/*',
],
use OpenB8\WebmanTrace\TraceService;
$config = config('plugin.openb8.webman-trace.app');
$traceService = new TraceService($config);
// 手动记录 SQL
$traceService->logSql(
'SELECT * FROM users WHERE id = ?',
[123],
25.6 // 执行时间(毫秒)
);
// 手动记录异常
try {
// 业务代码
} catch (\Exception $e) {
$traceService->logException($e, $request);
}
'console_output' => [
'enable' => true,
'verbose' => true, // 显示详细信息,便于调试
'beautiful' => true, // 美化输出
],
'log_body' => [
'request' => true, // 记录请求参数
'response' => true, // 记录响应数据
],
'console_output' => [
'enable' => false, // 关闭控制台输出,减少性能影响
],
'log_body' => [
'request' => false, // 关闭请求体记录,减少日志体积
'response' => false, // 关闭响应体记录
],
'slow_query_threshold' => 100, // 降低慢查询阈值
<?php
namespace app\controller;
use support\Request;
use support\Response;
class ApiController
{
/**
* 用户注册
*/
public function register(Request $request): Response
{
trace_info('开始用户注册', [
'ip' => $request->getRealIp(),
'user_agent' => $request->header('user-agent')
]);
try {
// 验证参数
$username = $request->post('username');
$email = $request->post('email');
$password = $request->post('password');
if (empty($username) || empty($email) || empty($password)) {
return jsont_error('参数不完整', 1001, [
'required_fields' => ['username', 'email', 'password']
], 400);
}
// 检查用户是否存在
if ($this->userExists($email)) {
trace_warning('用户注册失败:邮箱已存在', ['email' => $email]);
return jsont_error('邮箱已被注册', 1002, null, 409);
}
// 创建用户
$user = $this->createUser($username, $email, $password);
trace_info('用户注册成功', ['user_id' => $user->id]);
return jsont_success([
'user' => [
'id' => $user->id,
'username' => $user->username,
'email' => $user->email,
'created_at' => $user->created_at
]
], '注册成功');
} catch (\Exception $e) {
trace_error('用户注册异常', [
'error' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine()
]);
return jsont_error('注册失败,请稍后重试', 5000, null, 500);
}
}
/**
* 获取用户列表(分页)
*/
public function userList(Request $request): Response
{
$page = max(1, (int)$request->get('page', 1));
$pageSize = min(100, max(1, (int)$request->get('page_size', 15)));
$keyword = $request->get('keyword', '');
trace_info('获取用户列表', [
'page' => $page,
'page_size' => $pageSize,
'keyword' => $keyword
]);
try {
$users = $this->searchUsers($keyword, $page, $pageSize);
$total = $this->getUserCount($keyword);
return jsont_paginate($users, $total, $page, $pageSize, '获取成功');
} catch (\Exception $e) {
return jsont_error('获取用户列表失败', 3001);
}
}
/**
* 批量操作示例
*/
public function batchUpdate(Request $request): Response
{
$userIds = $request->post('user_ids', []);
$status = $request->post('status');
if (empty($userIds) || !is_array($userIds)) {
return jsont_error('用户ID列表不能为空', 4001);
}
trace_info('批量更新用户状态', [
'user_ids' => $userIds,
'status' => $status,
'count' => count($userIds)
]);
try {
$updated = 0;
$failed = [];
foreach ($userIds as $userId) {
try {
$this->updateUserStatus($userId, $status);
$updated++;
} catch (\Exception $e) {
$failed[] = $userId;
trace_warning('更新用户状态失败', [
'user_id' => $userId,
'error' => $e->getMessage()
]);
}
}
$result = [
'updated' => $updated,
'failed' => $failed,
'total' => count($userIds)
];
if ($updated > 0) {
trace_info('批量更新完成', $result);
return jsont_success($result, "成功更新 {$updated} 个用户");
} else {
return jsont_error('批量更新失败', 4002, $result);
}
} catch (\Exception $e) {
return jsont_error('批量更新异常', 5001);
}
}
// 私有方法示例...
private function userExists(string $email): bool
{
// 模拟数据库查询
// return User::where('email', $email)->exists();
return false;
}
private function createUser(string $username, string $email, string $password): object
{
// 模拟用户创建
return (object)[
'id' => rand(1000, 9999),
'username' => $username,
'email' => $email,
'created_at' => date('Y-m-d H:i:s')
];
}
}
检查项:
config/plugin/openb8/webman-trace/app.phpphp start.php restartenable 是否为 true解决方法:
// 检查配置文件
'console_output' => [
'enable' => true, // 确保启用
'beautiful' => true, // 确保开启美化
'levels' => ['request', 'response', 'exception', 'slow_query'],
],
检查项:
http://127.0.0.1:8787/trace'web_interface' => ['enable' => true]trace123解决方法:
'handle_404' => [
'enable' => true, // 启用404追踪
'custom_response' => false, // 只记录,不覆盖原有404
],
原因: 需要数据库ORM支持 解决方法:
# 安装支持的ORM
composer require topthink/think-orm
# 或
composer require illuminate/database
解决方法:
rm runtime/logs/trace.log优化建议:
// 生产环境配置
'console_output' => ['enable' => false], // 关闭控制台输出
'log_body' => ['request' => false, 'response' => false], // 关闭body记录
'debug_only' => true, // 仅在调试模式记录
欢迎提交 PR 和 Issue!
git checkout -b feature/new-featuregit commit -m 'Add new feature'git push origin feature/new-featureMIT License - 详见 LICENSE 文件
OpenB8 - 每个字节,都是起点
OpenB8 是一个专注于高质量开源项目的组织,致力于为开发者提供优秀的工具和解决方案。
🎉 享受愉快的开发体验!
如果这个插件对你有帮助,请给我们一个 ⭐ Star!