调试工具
Debug 模块提供两个互补的运行时自省工具:
- Inspect — HTTP/WebSocket 调试服务器,用于实时监控和控制
- Tracer — Chrome 追踪格式的性能分析器
两者都可在编译时完全剥离:设置 INSPECT_DISABLE=ON 和不定义 ENABLE_TRACE_RECORDING。
Inspect — HTTP/WebSocket 调试服务器
Inspect 提供内置 HTTP 服务器,用于在运行时暴露内部状态、指标和控制接口。支持 REST 风格的路由和 WebSocket 发布/订阅,用于实时数据流。
头文件
cpp
#include "xtils/debug/inspect.h"初始化
cpp
auto& inspect = Inspect::Get(); // 单例
inspect.Init("127.0.0.1", 8080);
inspect.Stop();注册路由
cpp
// 带描述的路由(显示在内置 Web 控制台中)
inspect.Route("/debug/stats", "应用统计",
[](const Inspect::Request& req, Inspect::Response& resp) {
Json stats;
stats["uptime_s"] = GetUptime();
stats["requests"] = request_count;
resp = Inspect::Json(stats);
});
// 静态内容
inspect.Static("/debug/dashboard", dashboard_html, "text/html");响应辅助方法
cpp
static Inspect::Response Json(const xtils::Json& json);
static Inspect::Response Text(const std::string& text);
static Inspect::Response Html(const std::string& html);
static Inspect::Response Error(const std::string& message);
static Inspect::Response Success(const std::string& message = "OK");API 方法
cpp
auto& inspect = Inspect::Get();
// 查询路由
bool exists = inspect.HasRoute("/debug/fsm");
auto routes = inspect.GetRoutes(); // 返回已注册 HTTP 路由列表
auto ws_routes = inspect.GetWebSocketRoutes(); // 返回已注册 WebSocket 路由列表
// 取消注册路由
inspect.Unregister("/debug/fsm");
// 服务器状态
bool running = inspect.IsRunning();
auto info = inspect.GetServerInfo(); // 返回地址、端口等信息
// 订阅者
size_t count = inspect.GetSubscriberCount("/debug/metrics");
// CORS 配置
inspect.SetCORS("*"); // 允许所有来源
inspect.SetCORS("http://localhost:3000"); // 限定来源WebSocket 发布/订阅
cpp
// 注册 WebSocket 端点
inspect.WebSocket("/debug/metrics", "实时指标流",
[](const Inspect::Request& req, Inspect::Response& resp) {
resp = Inspect::Success();
});
// 向所有连接的客户端发布
Json metrics;
metrics["cpu"] = cpu_percent;
metrics["memory_mb"] = memory_mb;
inspect.Publish("/debug/metrics", metrics);
// 检查是否有人在监听(避免昂贵的序列化)
if (inspect.HasSubscribers("/debug/metrics")) {
inspect.Publish("/debug/metrics", CollectMetrics().dump());
}
// 获取详细发布结果
auto result = inspect.PublishWithResult("/debug/metrics", message);
if (result.HasFailures()) {
LogW("发布失败: %zu", result.failed_count);
}Web 控制台
Inspect 内置双栏 Web 控制台(访问根路径即可打开):
- 左栏:已注册的路由列表,点击即可发起请求
- 右栏上方:HTTP 面板 — 支持 GET/POST,自动 JSON 格式化响应
- 右栏下方:WebSocket 面板 — 实时消息流,颜色区分收发/系统/错误
无需额外配置,启动 Inspect 服务器后浏览器访问即可使用。
注意:Web 控制台的 HTML 源码维护在
src/debug/inspect_page.html,通过cmake/embed_file.cmake嵌入到二进制中。
宏(禁用时零开销)
当定义 INSPECT_DISABLE 时,这些宏编译为空:
cpp
// HTTP 路由 — req 和 resp 在 body 中可用
INSPECT("/debug/fsm", "FSM 状态", {
resp = Inspect::Json(fsm.ToJson());
});
// WebSocket 端点
INSPECT_WS("/debug/events", "实时事件", {
resp = Inspect::Success();
});
// 暴露变量为 JSON {"value": expr}
INSPECT_VAR("/debug/counter", counter.load());
// 静态内容
INSPECT_STATIC("/debug/dashboard", dashboard_html, "text/html");
// 发布文本数据
INSPECT_PUBLISH("/debug/events", event_json.dump());
// 发布二进制数据
INSPECT_PUBLISH_BIN("/debug/binary", binary_data);用例:实时仪表板
cpp
class MonitorService : public Service<MonitorService> {
public:
MonitorService() : Service("monitor") {}
void Init() override {
INSPECT_WS("/debug/live", "实时指标", {
resp = Inspect::Success();
});
INSPECT_VAR("/debug/connections", GetConnectionCount());
ctx->Every(1000, [this]() {
if (!Inspect::Get().HasSubscribers("/debug/live")) return;
Json m;
m["timestamp"] = SteadyTimer::GetCurrentTimestampMs();
m["connections"] = GetConnectionCount();
INSPECT_PUBLISH("/debug/live", m.dump());
});
}
};Tracer — Chrome 追踪格式
Tracer 以 Chrome 追踪格式记录作用域事件,可在 chrome://tracing 或 Perfetto UI 中查看。
头文件
cpp
#include "xtils/debug/tracer.h"启用
Tracer 在编译时选择启用:
cpp
#define ENABLE_TRACE_RECORDING // 必须在 #include 之前
#include "xtils/debug/tracer.h"不定义 ENABLE_TRACE_RECORDING 时,所有追踪宏编译为空。
宏
cpp
TRACE_SCOPE("ProcessFrame") // 作用域事件(RAII)
TRACE_INSTANT("FrameReady") // 瞬时事件
TRACE_SAVE("trace.json") // 保存到文件示例:帧循环分析
cpp
#define ENABLE_TRACE_RECORDING
#include <xtils/debug/tracer.h>
void GameLoop() {
while (running) {
TRACE_SCOPE("Frame");
{
TRACE_SCOPE("Physics");
UpdatePhysics();
}
{
TRACE_SCOPE("Render");
RenderScene();
}
}
}
TRACE_SAVE("game_trace.json");
// 在 chrome://tracing 或 https://ui.perfetto.dev/ 中打开查看追踪
- 运行启用追踪记录的应用
- 调用
TRACE_SAVE("output.json") - 打开 Chrome,导航到
chrome://tracing - 点击"Load"并选择追踪文件
- 或使用 Perfetto UI 获得更现代的查看器
编译时剥离
| 模块 | 禁用标志 | 效果 |
|---|---|---|
| Inspect | INSPECT_DISABLE=ON(CMake) | INSPECT、INSPECT_WS、INSPECT_VAR、INSPECT_STATIC、INSPECT_PUBLISH、INSPECT_PUBLISH_BIN 宏变为空操作 |
| Tracer | 不定义 ENABLE_TRACE_RECORDING | 所有 TRACE_* 宏变为空操作 |
这意味着你可以在代码中随处添加调试工具,在生产构建中完全零运行时开销。
完整示例
cpp
#define ENABLE_TRACE_RECORDING
#include <xtils/app/service.h>
#include <xtils/debug/inspect.h>
#include <xtils/debug/tracer.h>
#include <xtils/logging/logger.h>
using namespace xtils;
class DebugService : public Service<DebugService> {
public:
DebugService() : Service("debug") {}
void Init() override {
auto port = config.GetOr<int>("inspect_port", 9090);
Inspect::Get().Init("0.0.0.0", port);
INSPECT("/system/info", "系统信息", {
Json info;
info["version"] = "1.0.0";
info["uptime"] = GetUptime();
info["pid"] = getpid();
resp = Inspect::Json(info);
});
INSPECT("/trace/save", "保存追踪数据", {
TRACE_SAVE("runtime_trace.json");
resp = Inspect::Success("追踪已保存");
});
LogI("[Debug] Inspect 服务器在端口 %d", port);
}
void Deinit() override {
TRACE_SAVE("shutdown_trace.json");
Inspect::Get().Stop();
}
};