#include "logger.h" #include #include #include #include #include #include #include #include #include #ifndef WIN32 #include #endif #define LOG_BUFFER_SIZE 4096 thread_local std::unique_ptr log_buffer{nullptr, nullptr}; std::mutex target_file_lock; std::unique_ptr file_stream; std::string logging_session; void logger::log_raw(logger::level::value level, const char* format, ...) { if(!log_buffer) { log_buffer = std::unique_ptr((char*) malloc(LOG_BUFFER_SIZE), ::free); } if(logging_session.empty()) { std::ostringstream os; os << std::uppercase << std::setfill('0') << std::setw(4) << std::hex << (uint32_t) rand(); logging_session = "[" + os.str() + "]"; } va_list arg_lst; va_start(arg_lst, format); auto result = vsnprintf(log_buffer.get(), LOG_BUFFER_SIZE, format, arg_lst); va_end(arg_lst); { std::lock_guard lock(target_file_lock); if(result < 0) { fprintf(stdout, "failed to format log message (%d)\n", result); if(file_stream) *file_stream << logging_session << "f ailed to format log message (" << result << ")\n"; } else { fprintf(stdout, "[%d] ", level); fwrite(log_buffer.get(), result, 1, stdout); fprintf(stdout, "\n"); if(file_stream) { *file_stream << logging_session << "[" << level << "] "; file_stream->write(log_buffer.get(), result); *file_stream << "\n"; } } } } void logger::flush() { std::lock_guard lock(target_file_lock); if(file_stream) { file_stream->flush(); } } bool logger::pipe_file(const std::string_view &target) { auto handle = std::make_unique(std::string(target.data(), target.size()), std::ofstream::app | std::ofstream::out); if(!handle->good()) { return false; } file_stream = std::move(handle); return true; }