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:
qing committed 2026-08-10 04:51:43 +00:00
1 parent 01ae877673
commit aa3741b861
32 files changed
+608 -2129

No files matched your search

+144
View File
@@ -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