invole c++
This commit is contained in:
100
cpp_ext/native_logger.cpp
Normal file
100
cpp_ext/native_logger.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user