feat(liblogc): 统一集中式日志客户端库 + 全量迁移
新增: - liblogc/: C++ 统一日志库 (libus_logc.so),支持 set_endpoint/set_service_name/set_level - pymsg/pymsg/logc.py: Python 统一日志模块,基于 AsyncRpcQueue C++ 迁移 (删除 6 份本地 LogC.hpp 副本): - ca, gateway: <us/LogC.hpp> + set_service_name - captcha2, confs2, smtp3: using qing::LogC + set_service_name - core: ConfsLogC → qing::LogC (ConfsTask.cpp) - 所有 Makefile 添加 -lus_logc Python 迁移 (6 个 log_client.py → 4 行薄包装): - smtp, redirect80, confs, captcha, dnfs, static - 全部委托到 pymsg.logc.LogClient Go (waf): 保持现状,自成体系
This commit is contained in:
1 parent
01ae877673
commit
aa3741b861
32 files changed
+608
-2129
No files matched your search
@@ -0,0 +1,144 @@
|
||||
#pragma once
|
||||
|
||||
/** LogC — 统一集中式日志客户端(C++ 版)
|
||||
*
|
||||
* 通过 pymsg TCP 调用 dbv2 execute 路由,逐条 INSERT 到 Logs 表。
|
||||
*
|
||||
* 设计要点:
|
||||
* - 异步非阻塞:基于 pmc::net::AsyncQueue 内存队列 + 后台线程批量推送
|
||||
* - fail-safe:db 服务不可用时静默丢弃(仅 stderr 提示),绝不影响业务
|
||||
* - 缓冲批量:队列满 50 条或超时 2 秒时自动 flush
|
||||
* - 背压保护:队列上限 10000 条,满时丢最旧日志,防止内存无限增长
|
||||
* - 级别过滤:set_level() 设定阈值,低于阈值的日志直接丢弃
|
||||
* - 可配置 endpoint / service_name,各服务复用同一份库
|
||||
*
|
||||
* 用法:
|
||||
* #include <us/LogC.hpp>
|
||||
*
|
||||
* // 启动时配置(默认 127.0.0.1:8005)
|
||||
* qing::LogC::instance().set_endpoint("127.0.0.1", 8005);
|
||||
* qing::LogC::instance().set_service_name("gateway-log");
|
||||
* qing::LogC::instance().set_level("warn");
|
||||
*
|
||||
* qing::LogC::instance().info("gateway", "启动完成");
|
||||
* qing::LogC::instance().error("gateway", "连接失败",
|
||||
* std::nullopt, R"({"errno":111})");
|
||||
*
|
||||
* // 进程退出前调用(幂等)
|
||||
* qing::LogC::instance().shutdown();
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// forward-declare: 避免在头文件中拉入 AsyncQueue 模板
|
||||
namespace pmc { namespace net {
|
||||
template <typename T> class AsyncQueue;
|
||||
}}
|
||||
|
||||
namespace qing {
|
||||
|
||||
class LogC {
|
||||
public:
|
||||
struct Entry {
|
||||
std::string service;
|
||||
std::string level;
|
||||
std::string message;
|
||||
std::optional<std::string> trace_id;
|
||||
std::optional<std::string> extra; // 已序列化的 JSON 字符串(存 Logs.extra TEXT)
|
||||
};
|
||||
|
||||
// 日志级别 → 数值(大写兼容)
|
||||
static const std::unordered_map<std::string, int>& level_order() {
|
||||
static const std::unordered_map<std::string, int> k = {
|
||||
{"debug", 0}, {"info", 1}, {"warn", 2}, {"warning", 2},
|
||||
{"error", 3}, {"critical", 3},
|
||||
{"DEBUG", 0}, {"INFO", 1}, {"WARN", 2}, {"WARNING", 2},
|
||||
{"ERROR", 3}, {"CRITICAL", 3},
|
||||
};
|
||||
return k;
|
||||
}
|
||||
|
||||
static LogC& instance() {
|
||||
static LogC inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
// ---- 配置(启动时调用,线程安全)-------------------------------------
|
||||
|
||||
void set_endpoint(const std::string& addr, int port);
|
||||
void set_service_name(const std::string& name);
|
||||
|
||||
// 设置日志级别阈值(debug|info|warn|error,大小写不限)
|
||||
void set_level(const std::string& level);
|
||||
|
||||
// ---- 推送接口(非阻塞,立即返回)-------------------------------------
|
||||
|
||||
void push(const std::string& service, const std::string& level,
|
||||
const std::string& message,
|
||||
std::optional<std::string> trace_id = std::nullopt,
|
||||
std::optional<std::string> extra = std::nullopt);
|
||||
|
||||
void debug(const std::string& service, const std::string& message,
|
||||
std::optional<std::string> trace_id = std::nullopt,
|
||||
std::optional<std::string> extra = std::nullopt) {
|
||||
push(service, "DEBUG", message, std::move(trace_id), std::move(extra));
|
||||
}
|
||||
void info(const std::string& service, const std::string& message,
|
||||
std::optional<std::string> trace_id = std::nullopt,
|
||||
std::optional<std::string> extra = std::nullopt) {
|
||||
push(service, "INFO", message, std::move(trace_id), std::move(extra));
|
||||
}
|
||||
void warning(const std::string& service, const std::string& message,
|
||||
std::optional<std::string> trace_id = std::nullopt,
|
||||
std::optional<std::string> extra = std::nullopt) {
|
||||
push(service, "WARNING", message, std::move(trace_id), std::move(extra));
|
||||
}
|
||||
void error(const std::string& service, const std::string& message,
|
||||
std::optional<std::string> trace_id = std::nullopt,
|
||||
std::optional<std::string> extra = std::nullopt) {
|
||||
push(service, "ERROR", message, std::move(trace_id), std::move(extra));
|
||||
}
|
||||
void critical(const std::string& service, const std::string& message,
|
||||
std::optional<std::string> trace_id = std::nullopt,
|
||||
std::optional<std::string> extra = std::nullopt) {
|
||||
push(service, "CRITICAL", message, std::move(trace_id), std::move(extra));
|
||||
}
|
||||
|
||||
// ---- 生命周期 -------------------------------------------------------
|
||||
|
||||
void flush(); // 手动 flush 当前积攒批次,等待完成
|
||||
void shutdown(); // 停止后台线程并 flush 剩余日志(幂等)
|
||||
|
||||
private:
|
||||
LogC();
|
||||
~LogC();
|
||||
|
||||
LogC(const LogC&) = delete;
|
||||
LogC& operator=(const LogC&) = delete;
|
||||
|
||||
void _send_batch(std::vector<Entry>&& batch);
|
||||
static std::string _utc_now_iso();
|
||||
|
||||
// ---- 配置项 ---------------------------------------------------------
|
||||
std::string _db_addr = "127.0.0.1";
|
||||
int _db_port = 8005;
|
||||
std::string _service_name = "log";
|
||||
std::mutex _endpoint_mtx; // 保护 _db_addr/_db_port/_service_name
|
||||
std::atomic<int> _level_threshold{1}; // 默认 INFO(1)
|
||||
|
||||
static constexpr size_t _BATCH_SIZE = 50;
|
||||
static constexpr double _FLUSH_INTERVAL = 2.0;
|
||||
static constexpr size_t _MAX_QUEUE_SIZE = 10000;
|
||||
static constexpr double _TIMEOUT = 5.0;
|
||||
|
||||
// ---- 核心队列(unique_ptr 延迟到 .cpp 中实例化,保持头文件轻量)----
|
||||
std::unique_ptr<pmc::net::AsyncQueue<Entry>> _queue;
|
||||
};
|
||||
|
||||
} // namespace qing
|
||||
Reference in new issue
Block a user