2#ifndef _LOGIT_FILE_LOGGER_HPP_INCLUDED
3#define _LOGIT_FILE_LOGGER_HPP_INCLUDED
21#include <time_shield/time_parser.hpp>
25#if defined(__EMSCRIPTEN__)
27 class FileLogger :
public ILogger {
41 FileLogger(
const std::string&,
const bool& =
true,
const int& = 30,
42 const uint64_t& = 0,
const uint32_t& = 0,
43 const bool& =
false, std::string = {}) { warn(); }
45 void log(
const LogRecord&,
const std::string&)
override { warn(); }
51 void wait()
override {}
54 void warn()
const { std::cerr <<
"FileLogger is not supported under Emscripten" << std::endl; }
102 const std::string& directory,
103 const bool& async =
true,
104 const int& auto_delete_days = 30) {
107 m_config.auto_delete_days = auto_delete_days;
113 const std::string& directory,
115 const int& auto_delete_days,
116 uint64_t max_file_size_bytes,
117 uint32_t max_rotated_files,
118 bool compress_rotated =
false,
119 std::string compress_cmd = {}) {
142 void log(
const LogRecord& record,
const std::string& message)
override {
145 std::lock_guard<std::mutex> lock(
m_mutex);
148 }
catch (
const std::exception& e) {
149 std::cerr <<
"Log error: " << e.what() << std::endl;
155 std::lock_guard<std::mutex> lock(
m_mutex);
158 }
catch (
const std::exception& e) {
159 std::cerr <<
"Log async log error: " << e.what() << std::endl;
176 return std::string();
239 std::lock_guard<std::mutex> lock(
m_mutex);
244 }
catch (
const std::exception& e) {
245 std::cerr <<
"Initialization error: " << e.what() << std::endl;
252 std::lock_guard<std::mutex> lock(
m_mutex);
290 throw std::runtime_error(
"Failed to open log file: " +
m_file_path);
292 m_file.seekp(0, std::ios::end);
300 std::string date_str = time_shield::to_iso8601_date(date_ts);
307 void write_log(
const std::string& message,
const int64_t& timestamp_ms) {
308 const int64_t message_date_ts = time_shield::start_of_day(time_shield::ms_to_sec(timestamp_ms));
312 if (
m_config.max_file_size_bytes > 0) {
313 const uint64_t add =
static_cast<uint64_t
>(message.size() + 1);
319 m_file << message << std::endl;
330 const std::string cur = dir +
"/" + base +
".log";
333# if __cplusplus >= 201703L
335 rotated = dir +
"/" + base +
"." + std::to_string(idx) +
".log";
336 if (!fs::exists(rotated))
break;
339 auto file_exists = [](
const std::string& path) {
341 std::ifstream f(utf8_to_ansi(path).c_str());
343 std::ifstream f(path.c_str());
348 rotated = dir +
"/" + base +
"." + std::to_string(idx) +
".log";
349 if (!file_exists(rotated))
break;
353 std::rename(utf8_to_ansi(cur).c_str(), utf8_to_ansi(rotated).c_str());
355 std::rename(cur.c_str(), rotated.c_str());
359 std::string cmd =
m_config.compress_cmd;
360 size_t pos = cmd.find(
"{file}");
361 if (pos != std::string::npos) cmd.replace(pos, 6,
"\"" + rotated +
"\"");
362 std::system(cmd.c_str());
365 if (
m_config.max_rotated_files > 0) {
374# if __cplusplus >= 201703L
375 std::vector<std::pair<uint32_t, fs::path>> files;
376 std::regex pattern(base + R
"(\.(\d+)\.log(\..*)?)");
377 for (
const auto& entry : fs::directory_iterator(dir)) {
378 if (!fs::is_regular_file(entry.status()))
continue;
380 std::string name = entry.path().filename().string();
381 if (std::regex_match(name, m, pattern)) {
382 uint32_t idx =
static_cast<uint32_t
>(std::stoul(m[1].str()));
383 files.emplace_back(idx, entry.path());
386 if (files.size() <= max_files)
return;
387 std::sort(files.begin(), files.end(), [](
const std::pair<uint32_t, fs::path>& a,
const std::pair<uint32_t, fs::path>& b) { return a.first < b.first; });
388 size_t to_remove = files.size() - max_files;
389 for (
size_t i = 0; i < to_remove; ++i) {
390 fs::remove(files[i].second);
393 std::vector<std::pair<uint32_t, std::string>> files;
394 std::regex pattern(base + R
"(\.(\d+)\.log(\..*)?)");
396 for (
const auto& path : file_list) {
397 std::string name = path.substr(path.find_last_of(
"/\\") + 1);
399 if (std::regex_match(name, m, pattern)) {
400 uint32_t idx =
static_cast<uint32_t
>(std::stoul(m[1].str()));
401 files.emplace_back(idx, path);
404 if (files.size() <= max_files)
return;
405 std::sort(files.begin(), files.end(), [](
const std::pair<uint32_t, std::string>& a,
const std::pair<uint32_t, std::string>& b) { return a.first < b.first; });
406 size_t to_remove = files.size() - max_files;
407 for (
size_t i = 0; i < to_remove; ++i) {
409 remove(utf8_to_ansi(files[i].second).c_str());
411 remove(files[i].second.c_str());
420# if __cplusplus >= 201703L
427 if (!fs::exists(dir_path) ||
428 !fs::is_directory(dir_path)) {
432 for (
const auto& entry : fs::directory_iterator(dir_path)) {
433 if (!fs::is_regular_file(entry.status()))
continue;
434 std::string filename = entry.path().filename().string();
437 if (file_date_ts < threshold_ts) {
438 fs::remove(entry.path());
444 for (
const auto& file_path : file_list) {
446 std::string filename = file_path.substr(file_path.find_last_of(
"/\\") + 1);
449 if (file_date_ts < threshold_ts) {
451 remove(utf8_to_ansi(file_path).c_str());
453 remove(file_path.c_str());
465 return filename.size() >= 10 && filename[4] ==
'-' && filename[7] ==
'-';
472 return time_shield::ts(filename.substr(0, 10));
Defines the interface for loggers used in the logging system.
std::mutex m_mutex
Mutex to protect file operations.
int64_t m_current_date_ts
Timestamp of the current log file's date.
void stop_logging()
Stops the logging process by closing the file and waiting for tasks.
void initialize_directory()
Initializes the logging directory.
std::string get_last_log_file_name() const
Retrieves the last log file name.
void remove_old_logs()
Removes old log files based on the auto-delete days configuration.
int64_t get_date_ts_from_filename(const std::string &filename) const
Extracts the date timestamp from the log filename.
FileLogger(const Config &config)
Constructor with custom configuration.
int64_t current_timestamp_ms() const
Gets the current timestamp in milliseconds.
Config m_config
Configuration for the file logger.
int64_t get_time_since_last_log() const
Retrieves the time since the last log.
std::string get_last_log_file_path() const
Retrieves the last log file path.
FileLogger(const std::string &directory, const bool &async=true, const int &auto_delete_days=30)
Constructor with directory and asynchronous flag.
void rotate_current_file()
std::mutex m_file_path_mutex
Mutex to protect file path operations.
uint64_t m_current_file_size
Current size of the log file.
FileLogger(const std::string &directory, const bool &async, const int &auto_delete_days, uint64_t max_file_size_bytes, uint32_t max_rotated_files, bool compress_rotated=false, std::string compress_cmd={})
Constructor with directory, size-based rotation and additional options.
void set_log_level(LogLevel level) override
Sets the minimal log level for this logger.
int64_t get_int_param(const LoggerParam ¶m) const override
Retrieves an integer parameter from the logger.
std::ofstream m_file
Output file stream for logging.
std::atomic< int64_t > m_last_log_ts
Timestamp of the last log.
virtual ~FileLogger()
Destructor to stop logging and close file.
void start_logging()
Starts the logging process by initializing the file and directory.
bool is_valid_log_filename(const std::string &filename) const
Checks if the filename matches the log file naming pattern.
std::string get_string_param(const LoggerParam ¶m) const override
Retrieves a string parameter from the logger.
int64_t get_last_log_ts() const
Retrieves the timestamp of the last log.
std::string m_file_path
Path of the currently open log file.
void log(const LogRecord &record, const std::string &message) override
Logs a message to a file with thread safety.
FileLogger()
Default constructor that uses default configuration.
int64_t get_current_utc_date_ts() const
Gets the current UTC date timestamp in seconds.
void open_log_file(const int64_t &date_ts)
Opens a new log file based on the provided date timestamp.
std::string get_directory_path() const
Gets the full path to the logging directory.
void write_log(const std::string &message, const int64_t ×tamp_ms)
Writes a log message to the file.
void enforce_rotation_retention(const std::string &base, uint32_t max_files, const std::string &dir)
std::string create_file_path(int64_t date_ts) const
Creates a file path for the log file based on the date timestamp.
LogLevel get_log_level() const override
Gets the minimal log level for this logger.
std::atomic< int > m_log_level
void wait() override
Waits for all asynchronous tasks to complete.
std::string m_file_name
Name of the currently open log file.
double get_float_param(const LoggerParam ¶m) const override
Retrieves a floating-point parameter from the logger.
Interface for loggers that handle log message output.
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.
Configuration for the file logger.
std::string compress_cmd
External command used for compression.
bool compress_rotated
Whether to compress rotated files.
uint64_t max_file_size_bytes
Max size for log file before rotation (0 = off).
uint32_t max_rotated_files
Number of rotated files to keep (0 = unlimited).
int auto_delete_days
Number of days after which old log files are deleted.
bool async
Flag indicating whether logging should be asynchronous.
std::string directory
Directory where log files are stored.
Stores log metadata and content.
const int64_t timestamp_ms
Timestamp in milliseconds.