2#ifndef _LOGIT_UNIQUE_FILE_LOGGER_HPP_INCLUDED 
    3#define _LOGIT_UNIQUE_FILE_LOGGER_HPP_INCLUDED 
   21#include <unordered_map> 
   25#if defined(__EMSCRIPTEN__) 
   27    class UniqueFileLogger : 
public ILogger {
 
   38        UniqueFileLogger(
const std::string&, 
bool = 
true, 
int = 30, 
size_t = 8) { warn(); }
 
   40        void log(
const LogRecord&, 
const std::string&)
 override { warn(); }
 
   46        void wait()
 override {}
 
   49        void warn()
 const { std::cerr << 
"UniqueFileLogger is not supported under Emscripten" << std::endl; }
 
   96            const std::string& directory,
 
   98            int auto_delete_days = 30,
 
   99            size_t hash_length = 8) {
 
  102            m_config.auto_delete_days = auto_delete_days;
 
 
  118        void log(
const LogRecord& record, 
const std::string& message)
 override {
 
  122                std::lock_guard<std::mutex> lock(
m_mutex);
 
  123                std::string file_path;
 
  126                } 
catch (
const std::exception& e) {
 
  128                    std::cerr << 
"Log error: " << e.what() << std::endl;
 
  134                    if (!file_path.empty()) {
 
  142                if (!file_path.empty()) {
 
  143                    it->second.last_file_path = file_path;
 
  146                    it->second.last_file_path = 
"Not available";
 
  147                    it->second.last_file_name = 
"Not available";
 
  155                } 
catch (
const std::exception& e) {
 
  156                    std::cerr << 
"Log error: " << e.what() << std::endl;
 
  167                std::lock_guard<std::mutex> lock(
m_mutex);
 
  168                std::string file_path;
 
  170                    file_path = 
write_log(message, timestamp_ms);
 
  171                } 
catch (
const std::exception& e) {
 
  173                    std::cerr << 
"Async log error: " << e.what() << std::endl;
 
  180                if (!file_path.empty()) {
 
  181                    it->second.last_file_path = file_path;
 
  184                    it->second.last_file_path = 
"Not available";
 
  185                    it->second.last_file_name = 
"Not available";
 
  187                it->second.pending_logs--;
 
  189                if (it->second.pending_logs == 0) {
 
  196                } 
catch (
const std::exception& e) {
 
  197                    std::cerr << 
"Async log error: " << e.what() << std::endl;
 
 
  214            return std::string();
 
 
  290            std::lock_guard<std::mutex> lock(
m_mutex);
 
  294            } 
catch (
const std::exception& e) {
 
  295                std::cerr << 
"Initialization error: " << e.what() << std::endl;
 
 
  319        std::string 
write_log(
const std::string& message, 
const int64_t& timestamp_ms) {
 
  322            std::ofstream file(utf8_to_ansi(file_path), std::ios_base::binary);
 
  324            std::ofstream file(file_path, std::ios_base::binary);
 
  326            if (!file.is_open()) {
 
  327                throw std::runtime_error(
"Failed to open log file: " + file_path);
 
  329            file.write(message.data(), message.size());
 
 
  347            const auto dt = time_shield::to_date_time_ms<time_shield::DateTimeStruct>(timestamp_ms);
 
  348            char buffer[32] = {0};
 
  349            snprintf(buffer, 
sizeof(buffer), 
"%lld-%.2d-%.2d_%.2d-%.2d-%.2d-%.3d", dt.year, dt.mon, dt.day, dt.hour, dt.min, dt.sec, dt.ms);
 
  350            return std::string(buffer);
 
 
  357            static const char charset[] =
 
  359                "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
  360                "abcdefghijklmnopqrstuvwxyz";
 
  361            static thread_local std::mt19937 generator(std::random_device{}());
 
  362            static thread_local std::uniform_int_distribution<size_t> distribution(0, 
sizeof(charset) - 2);
 
  365            hash.reserve(length);
 
  366            for (
size_t i = 0; i < length; ++i) {
 
  367                hash += charset[distribution(generator)];
 
 
  374            const int64_t threshold_ts =
 
  376                (
m_config.auto_delete_days * time_shield::SEC_PER_DAY);
 
  377#           if __cplusplus >= 201703L 
  385            if (!fs::exists(dir_path) || !fs::is_directory(dir_path)) {
 
  389            for (
const auto& entry : fs::directory_iterator(dir_path)) {
 
  390                if (!fs::is_regular_file(entry.status())) 
continue;
 
  391                std::string filename = entry.path().filename().string();
 
  394                    if (file_ts < threshold_ts) {
 
  395                        fs::remove(entry.path());
 
  401            for (
const auto& file_path : file_list) {
 
  405                    if (file_ts < threshold_ts) {
 
  407                        remove(utf8_to_ansi(file_path).c_str());
 
  409                        remove(file_path.c_str());
 
 
  421            static const std::regex pattern(R
"((\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}-\d{3})-[a-zA-Z0-9]{1,}\.log)"); 
  422            return std::regex_match(filename, pattern);
 
 
  429            std::string datetime_str = filename.substr(0, 10); 
 
  430            return time_shield::ts(datetime_str);
 
 
  446            auto thread_id = std::this_thread::get_id();
 
  454                return it->second.last_file_name;
 
  456            return std::string();
 
 
  466            auto thread_id = std::this_thread::get_id();
 
  474                return it->second.last_file_path;
 
  476            return std::string();
 
 
 
Defines the interface for loggers used in the logging system.
 
Interface for loggers that handle log message output.
 
int64_t current_timestamp_ms() const
Gets the current timestamp in milliseconds.
 
std::string get_directory_path() const
Gets the full path to the logging directory.
 
std::string generate_fixed_length_hash(size_t length) const
Generates a fixed-length hash string.
 
void wait() override
Waits for all asynchronous tasks to complete.
 
int64_t get_last_log_ts() const
Retrieves the timestamp of the last log.
 
void initialize_directory()
Initializes the logging directory.
 
double get_float_param(const LoggerParam ¶m) const override
Retrieves a floating-point parameter from the logger.
 
std::string get_last_log_file_path() const
Retrieves the last log file path for the calling thread.
 
std::condition_variable m_pending_logs_cv
Condition variable to wait for pending logs to finish.
 
virtual ~UniqueFileLogger()
 
std::unordered_map< std::thread::id, ThreadLogInfo > m_thread_log_info
Map to store log information per thread.
 
UniqueFileLogger(const std::string &directory, bool async=true, int auto_delete_days=30, size_t hash_length=8)
Constructor with directory and asynchronous flag.
 
Config m_config
Configuration for the unique file logger.
 
UniqueFileLogger()
Default constructor that uses default configuration.
 
LogLevel get_log_level() const override
Gets the minimal log level for this logger.
 
UniqueFileLogger(const Config &config)
Constructor with custom configuration.
 
int64_t get_timestamp_from_filename(const std::string &filename) const
Extracts the timestamp from the filename.
 
void stop_logging()
Stops the logging process by waiting for tasks.
 
std::atomic< int64_t > m_last_log_ts
Timestamp of the last log.
 
std::string get_string_param(const LoggerParam ¶m) const override
Retrieves a string parameter from the logger.
 
void log(const LogRecord &record, const std::string &message) override
Logs a message to a unique file with thread safety.
 
void set_log_level(LogLevel level) override
Sets the minimal log level for this logger.
 
std::mutex m_mutex
Mutex to protect file operations.
 
std::string create_unique_file_path(const int64_t ×tamp_ms) const
Creates a unique file path based on the timestamp and a hash.
 
std::string format_timestamp(const int64_t ×tamp_ms) const
Formats the timestamp into a string with date and time.
 
std::string get_last_log_file_name() const
Retrieves the last log file name for the calling thread.
 
void remove_old_logs()
Removes old log files based on the auto-delete days configuration.
 
void start_logging()
Starts the logging process by initializing the directory and removing old logs.
 
int64_t get_int_param(const LoggerParam ¶m) const override
Retrieves an integer parameter from the logger.
 
std::mutex m_thread_log_info_mutex
Mutex to protect access to thread log information.
 
std::atomic< int > m_log_level
 
int64_t get_time_since_last_log() const
Retrieves the time elapsed since the last log.
 
std::string write_log(const std::string &message, const int64_t ×tamp_ms)
Writes a log message to a unique file.
 
bool is_valid_log_filename(const std::string &filename) const
Checks if the filename matches the log file naming pattern.
 
void add_task(std::function< void()> task)
Adds a task to the queue in a thread-safe manner.
 
void wait()
Waits for all tasks in the queue to be processed.
 
static TaskExecutor & get_instance()
Get the singleton instance of the TaskExecutor.
 
#define LOGIT_CURRENT_TIMESTAMP_MS()
Macro to get the current timestamp in milliseconds.
 
The primary namespace for the LogIt++ library.
 
std::vector< std::string > get_list_files(const std::string &path)
Recursively retrieves a list of all files in a directory.
 
@ LOG_LVL_TRACE
Trace level logging.
 
void create_directories(const std::string &path)
Creates directories recursively for the given path.
 
LoggerParam
Enumeration for different logger parameters that can be retrieved.
 
@ TimeSinceLastLog
The time elapsed since the last log in seconds.
 
@ LastLogTimestamp
The timestamp of the last log.
 
@ LastFileName
The name of the last file written to.
 
@ LastFilePath
The full path of the last file written to.
 
std::string get_file_name(const std::string &file_path)
Extracts the file name from a full file path.
 
std::string get_exec_dir()
Retrieves the directory of the executable file.
 
Stores log metadata and content.
 
std::thread::id thread_id
ID of the logging thread.
 
const int64_t timestamp_ms
Timestamp in milliseconds.
 
Configuration for the unique file logger.
 
int auto_delete_days
Number of days after which old log files are deleted.
 
std::string directory
Directory where log files are stored.
 
bool async
Flag indicating whether logging should be asynchronous.
 
size_t hash_length
Length of the hash used in filenames.
 
std::string last_file_path
 
ThreadLogInfo(const int pending_logs, const std::string last_file_path, const std::string last_file_name)
 
std::string last_file_name