#include "logger.h"
#include <cstring>
#include <iomanip>
DebugLogger &DebugLogger::getInstance() {
static DebugLogger instance;
return instance;
}
DebugLogger::~DebugLogger() { cleanup(); }
void DebugLogger::init(bool enable_debug, const char *log_file) {
std::lock_guard<std::mutex> lock(mutex_);
enabled_ = enable_debug;
if (!enabled_) {
return;
}
if (file_stream_.is_open()) {
file_stream_.close();
}
use_file_ = (log_file != nullptr && strlen(log_file) > 0);
if (use_file_) {
file_stream_.open(log_file, std::ios::out | std::ios::app);
if (!file_stream_.is_open()) {
std::cerr << "[CTP_DEBUG] 无法打开日志文件: " << log_file
<< ", 将使用控制台输出" << std::endl;
use_file_ = false;
}
}
}
void DebugLogger::cleanup() {
std::lock_guard<std::mutex> lock(mutex_);
if (file_stream_.is_open()) {
file_stream_.close();
}
enabled_ = false;
use_file_ = false;
}
void DebugLogger::debug(const char *file, int line, const char *func,
const char *format, ...) {
if (!enabled_) {
return;
}
va_list args;
va_start(args, format);
va_list args_copy;
va_copy(args_copy, args);
int len = vsnprintf(nullptr, 0, format, args_copy);
va_end(args_copy);
if (len < 0) {
va_end(args);
return;
}
std::string message(len + 1, '\0');
vsnprintf(&message[0], len + 1, format, args);
va_end(args);
message.resize(len);
std::ostringstream log_stream;
log_stream << "[" << getCurrentTimestamp() << "] "
<< "[DEBUG] "
<< "[" << extractFileName(file) << ":" << line << "] " << message;
std::string log_message = log_stream.str();
std::lock_guard<std::mutex> lock(mutex_);
if (use_file_ && file_stream_.is_open()) {
file_stream_ << log_message << std::endl;
file_stream_.flush(); } else {
std::cout << log_message << std::endl;
std::cout.flush();
}
}
std::string DebugLogger::getCurrentTimestamp() {
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) %
1000;
std::ostringstream oss;
oss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
oss << "." << std::setfill('0') << std::setw(3) << ms.count();
return oss.str();
}
std::string DebugLogger::getThreadId() {
#ifdef _WIN32
return std::to_string(GetCurrentThreadId());
#elif defined(__APPLE__) || defined(__linux__)
std::ostringstream oss;
oss << std::this_thread::get_id();
return oss.str();
#else
return "unknown";
#endif
}
std::string DebugLogger::extractFileName(const char *full_path) {
if (!full_path)
return "unknown";
const char *filename = full_path;
const char *last_slash = nullptr;
for (const char *p = full_path; *p; ++p) {
if (*p == '/' || *p == '\\') {
last_slash = p;
}
}
if (last_slash) {
filename = last_slash + 1;
}
return std::string(filename);
}
extern "C" {
void CTP_InitializeDebugLogging(const CtpLogConfig *config) {
if (!config) {
return;
}
DebugLogger::getInstance().init(config->enable_debug != 0,
config->log_file_path);
}
void CTP_CleanupDebugLogging() { DebugLogger::getInstance().cleanup(); }
}