#include #include #include "log_utils.h" LogBuffer::LogBuffer() : last_flush_time(0) {} LogBuffer& LogBuffer::operator<<(const std::string& value) { buffer.append(value); return *this; } LogBuffer& LogBuffer::operator<<(const char* value) { buffer.append(value); return *this; } LogBuffer& LogBuffer::operator<<(char value) { buffer.push_back(value); return *this; } LogBuffer& LogBuffer::append(const std::string& str) { buffer.append(str); return *this; } LogBuffer& LogBuffer::append(const char* str) { buffer.append(str); return *this; } LogBuffer& LogBuffer::append(const char* str, size_t len) { buffer.append(str, len); return *this; } LogBuffer& LogBuffer::write(const std::string& str) { buffer.append(str); return *this; } LogBuffer& LogBuffer::write(const char* str, size_t len) { buffer.append(str, len); return *this; } void LogBuffer::reset(uint64_t flush_time) { buffer.clear(); last_flush_time = flush_time; } void LogBuffer::set_last_flush_time(uint64_t flush_time) { last_flush_time = flush_time; } uint64_t LogBuffer::get_last_flush_time() const { return last_flush_time; } bool LogBuffer::empty() const { return buffer.empty(); } size_t LogBuffer::size() const { return buffer.size(); } const char* LogBuffer::data() const { return buffer.data(); } void LogBuffer::flush_to_file(std::fstream* logfile) { if (!logfile || buffer.empty()) { return; } logfile->write(buffer.data(), buffer.size()); } bool flush_and_rotate( LogBuffer& buffer, std::fstream*& logfile, unsigned int& current_log_size, unsigned int max_log_file_size, std::function lock_fn, std::function unlock_fn, std::function rotate_fn, uint64_t reset_time) { bool flushed = false; lock_fn(); if (logfile) { buffer.flush_to_file(logfile); current_log_size += buffer.size(); flushed = true; logfile->flush(); if (current_log_size > max_log_file_size && rotate_fn) { rotate_fn(); current_log_size = 0; } } unlock_fn(); if (flushed) { buffer.reset(reset_time); } return flushed; } LogBufferThreadContext::LogBufferThreadContext() : dist(0.0, 1.0) { // Seed the Mersenne Twister with multiple entropy sources std::random_device rd; std::seed_seq seed{ rd(), static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()), static_cast(pthread_self()) }; rng.seed(seed); } bool LogBufferThreadContext::should_log(int rate_limit) { return dist(rng) * static_cast(rate_limit) <= 1.0; } LogBufferThreadContext* GetLogBufferThreadContext(std::unordered_map>& log_thread_contexts, std::mutex& log_thread_contexts_lock, uint64_t current_time) { pthread_t tid = pthread_self(); std::lock_guard lock(log_thread_contexts_lock); auto it = log_thread_contexts.find(tid); if (it != log_thread_contexts.end()) { return it->second.get(); } // Context doesn't exist for this thread, create it with proper initialization auto new_context = std::make_unique(); // init() is already called in the constructor, which initializes both events and audit buffers new_context->events.set_last_flush_time(current_time); new_context->audit.set_last_flush_time(current_time); LogBufferThreadContext* ptr = new_context.get(); auto [insert_it, inserted] = log_thread_contexts.emplace(tid, std::move(new_context)); return inserted ? ptr : insert_it->second.get(); }