Files
archery/cpp_ext/native_logger.cpp

101 lines
2.8 KiB
C++
Raw Normal View History

2026-01-22 17:55:11 +08:00
#include "native_logger.hpp"
#include <cerrno>
#include <cstring>
#include <mutex>
#include <string>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
namespace netcore {
static std::mutex g_mu;
static int g_fd = -1;
static std::string g_path = "netcore.log";
static LogLevel g_level = LogLevel::kDebug; //LogLevel::kInfo;
static const char* level_name(LogLevel lvl) {
switch (lvl) {
case LogLevel::kError: return "E";
case LogLevel::kWarn: return "W";
case LogLevel::kInfo: return "I";
case LogLevel::kDebug: return "D";
default: return "?";
}
}
static void ensure_open_locked() {
if (g_path.empty()) return;
if (g_fd >= 0) return;
g_fd = ::open(g_path.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
}
void set_log_file(const std::string& path) {
std::lock_guard<std::mutex> lk(g_mu);
g_path = path;
if (g_fd >= 0) {
::close(g_fd);
g_fd = -1;
}
ensure_open_locked();
}
void set_log_level(LogLevel level) {
std::lock_guard<std::mutex> lk(g_mu);
g_level = level;
}
void log(LogLevel level, const std::string& msg) {
std::lock_guard<std::mutex> lk(g_mu);
if (static_cast<int>(level) > static_cast<int>(g_level)) return;
if (g_path.empty()) return;
ensure_open_locked();
if (g_fd < 0) {
// Last resort: stderr (avoid any Python APIs)
::write(STDERR_FILENO, msg.c_str(), msg.size());
::write(STDERR_FILENO, "\n", 1);
return;
}
// Timestamp: epoch milliseconds (simple and cheap)
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
// long long ms = (long long)ts.tv_sec * 1000LL + ts.tv_nsec / 1000000LL;
// 1. 将秒数转换为本地时间结构体 struct tm
struct tm *tm_info = localtime(&ts.tv_sec);
// 2. 准备一个缓冲区来存储时间字符串
char buffer[30];
// 3. 格式化秒的部分
// 格式: 年-月-日 时:分:秒
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
// 4. 计算毫秒部分并追加到字符串中
// ts.tv_nsec 是纳秒,除以 1,000,000 得到毫秒
char ms_buffer[8];
snprintf(ms_buffer, sizeof(ms_buffer), ".%03ld", ts.tv_nsec / 1000000);
// Build one line to keep writes atomic-ish
char head[256];
int n = ::snprintf(head, sizeof(head), "[%s%s] [%s] ", buffer, ms_buffer, level_name(level));
if (n < 0) n = 0;
::write(g_fd, head, (size_t)n);
::write(g_fd, msg.c_str(), msg.size());
::write(g_fd, "\n", 1);
}
void log_debug(const std::string& msg) { log(LogLevel::kDebug, msg); }
void log_info (const std::string& msg) { log(LogLevel::kInfo, msg); }
void log_warn (const std::string& msg) { log(LogLevel::kWarn, msg); }
void log_error(const std::string& msg) { log(LogLevel::kError, msg); }
} // namespace netcore