LogIt++
Loading...
Searching...
No Matches
FileLogger.hpp
Go to the documentation of this file.
1#ifndef _LOGIT_FILE_LOGGER_HPP_INCLUDED
2#define _LOGIT_FILE_LOGGER_HPP_INCLUDED
5
6#include "ILogger.hpp"
7#include <iostream>
8#include <fstream>
9#include <mutex>
10#include <atomic>
11#include <regex>
12#include <queue>
13#include <functional>
14
15namespace logit {
16
28 class FileLogger : public ILogger {
29 public:
30
33 struct Config {
34 std::string directory = "logs";
35 bool async = true;
37 };
38
42 }
43
46 FileLogger(const Config& config) : m_config(config) {
48 }
49
55 const std::string& directory,
56 const bool& async = true,
57 const int& auto_delete_days = 30) {
58 m_config.directory = directory;
59 m_config.async = async;
60 m_config.auto_delete_days = auto_delete_days;
62 }
63
65 virtual ~FileLogger() {
67 }
68
76 void log(const LogRecord& record, const std::string& message) override {
78 if (!m_config.async) {
79 std::lock_guard<std::mutex> lock(m_mutex);
80 try {
81 write_log(message, record.timestamp_ms);
82 } catch (const std::exception& e) {
83 std::cerr << "Log error: " << e.what() << std::endl;
84 }
85 return;
86 }
87 auto timestamp_ms = record.timestamp_ms;
88 TaskExecutor::get_instance().add_task([this, message, timestamp_ms]() {
89 std::lock_guard<std::mutex> lock(m_mutex);
90 try {
91 write_log(message, timestamp_ms);
92 } catch (const std::exception& e) {
93 std::cerr << "Log async log error: " << e.what() << std::endl;
94 }
95 });
96 }
97
101 std::string get_string_param(const LoggerParam& param) const override {
102 switch (param) {
105 case LoggerParam::LastLogTimestamp: return std::to_string(get_last_log_ts());
106 case LoggerParam::TimeSinceLastLog: return std::to_string(get_time_since_last_log());
107 default:
108 break;
109 };
110 return std::string();
111 }
112
116 int64_t get_int_param(const LoggerParam& param) const override {
117 switch (param) {
120 default:
121 break;
122 };
123 return 0;
124 }
125
129 double get_float_param(const LoggerParam& param) const override {
130 switch (param) {
131 case LoggerParam::LastLogTimestamp: return (double)get_last_log_ts() / 1000.0;
132 case LoggerParam::TimeSinceLastLog: return (double)get_time_since_last_log() / 1000.0;
133 default:
134 break;
135 };
136 return 0.0;
137 }
138
140 void wait() override {
141 if (!m_config.async) return;
143 }
144
145 private:
146 mutable std::mutex m_mutex;
148 std::ofstream m_file;
149 mutable std::mutex m_file_path_mutex;
150 std::string m_file_path;
151 std::string m_file_name;
152 int64_t m_current_date_ts = 0;
153 std::atomic<int64_t> m_last_log_ts = ATOMIC_VAR_INIT(0);
154
157 // потоки ввода-вывода (например, std::cin, std::cout, std::cerr) могут быть закрыты до завершения программы.
158 // В этом случае вызовы функций, которые используют потоки ввода-вывода (например, конструктор std::regex),
159 // могут приводить к нежелательным поведениям, таким как зависание или ошибки сегментации.
160 is_valid_log_filename("2024-01-01.log");
161 std::lock_guard<std::mutex> lock(m_mutex);
162 try {
166 } catch (const std::exception& e) {
167 std::cerr << "Initialization error: " << e.what() << std::endl;
168 }
169 }
170
173 wait();
174 std::lock_guard<std::mutex> lock(m_mutex);
175 if (m_file.is_open()) {
176 m_file.close();
177 }
178 }
179
184
187 std::string get_directory_path() const {
188# if defined(_WIN32)
189 return get_exec_dir() + "\\" + m_config.directory;
190# else
191 return get_exec_dir() + "/" + m_config.directory;
192# endif
193 }
194
197 void open_log_file(const int64_t& date_ts) {
198 if (m_file.is_open()) {
199 m_file.close();
200 }
201 m_current_date_ts = date_ts;
202 std::unique_lock<std::mutex> lock(m_file_path_mutex);
203 m_file_path = create_file_path(date_ts);
205 lock.unlock();
206# if defined(_WIN32)
207 m_file.open(utf8_to_ansi(m_file_path), std::ios_base::app);
208# else
209 m_file.open(m_file_path, std::ios_base::app);
210# endif
211 if (!m_file.is_open()) {
212 throw std::runtime_error("Failed to open log file: " + m_file_path);
213 }
214 }
215
219 std::string create_file_path(const int64_t& date_ts) const {
220 std::string date_str = time_shield::to_iso8601_date(date_ts);
221 return get_directory_path() + "/" + date_str + ".log";
222 }
223
227 void write_log(const std::string& message, const int64_t& timestamp_ms) {
228 const int64_t message_date_ts = time_shield::start_of_day(time_shield::ms_to_sec(timestamp_ms));
229 if (message_date_ts != m_current_date_ts) {
230 open_log_file(message_date_ts);
231 }
232 if (m_file.is_open()) {
233 m_file << message << std::endl;
234 }
236 }
237
240 const int64_t threshold_ts = m_current_date_ts - (time_shield::SEC_PER_DAY * m_config.auto_delete_days);
241# if __cplusplus >= 201703L
242# ifdef _WIN32
243 fs::path dir_path = fs::u8path(get_directory_path());
244# else
245 fs::path dir_path(get_directory_path());
246# endif
247
248 if (!fs::exists(dir_path) ||
249 !fs::is_directory(dir_path)) {
250 return;
251 }
252
253 for (const auto& entry : fs::directory_iterator(dir_path)) {
254 if (!fs::is_regular_file(entry.status())) continue;
255 std::string filename = entry.path().filename().string();
256 if (is_valid_log_filename(filename)) {
257 const int64_t file_date_ts = get_date_ts_from_filename(filename);
258 if (file_date_ts < threshold_ts) {
259 fs::remove(entry.path());
260 }
261 }
262 }
263# else
264 std::vector<std::string> file_list = get_list_files(get_directory_path());
265 for (const auto& file_path : file_list) {
266 // Извлекаем имя файла
267 std::string filename = file_path.substr(file_path.find_last_of("/\\") + 1);
268 if (is_valid_log_filename(filename)) {
269 const int64_t file_date_ts = get_date_ts_from_filename(filename);
270 if (file_date_ts < threshold_ts) {
271# if defined(_WIN32)
272 remove(utf8_to_ansi(file_path).c_str());
273# else
274 remove(file_path.c_str());
275# endif
276 }
277 }
278 }
279# endif
280 }
281
285 bool is_valid_log_filename(const std::string& filename) const {
286 static const std::regex pattern(R"((\d{4}-\d{2}-\d{2})\.log)");
287 return std::regex_match(filename, pattern);
288 }
289
293 int64_t get_date_ts_from_filename(const std::string& filename) const {
294 constexpr size_t EXTENSION_LENGTH = sizeof(".log") - 1;
295 return time_shield::ts(filename.substr(0, filename.size() - EXTENSION_LENGTH));
296 }
297
300 int64_t get_current_utc_date_ts() const {
301 return time_shield::start_of_day(time_shield::ms_to_sec(current_timestamp_ms()));
302 }
303
306 int64_t current_timestamp_ms() const {
307 return LOGIT_CURRENT_TIMESTAMP_MS();
308 }
309
312 std::string get_last_log_file_path() const {
313 std::lock_guard<std::mutex> lock(m_file_path_mutex);
314 return m_file_path;
315 }
316
319 std::string get_last_log_file_name() const {
320 std::lock_guard<std::mutex> lock(m_file_path_mutex);
321 return m_file_name;
322 }
323
326 int64_t get_last_log_ts() const {
327 return m_last_log_ts;
328 }
329
332 int64_t get_time_since_last_log() const {
333 return LOGIT_CURRENT_TIMESTAMP_MS() - m_last_log_ts;
334 }
335 }; // FileLogger
336
337}; // namespace logit
338
339#endif // _LOGIT_FILE_LOGGER_HPP_INCLUDED
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.
std::string create_file_path(const int64_t &date_ts) const
Creates a file path for the log file based on the date timestamp.
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.
std::mutex m_file_path_mutex
Mutex to protect file path operations.
int64_t get_int_param(const LoggerParam &param) 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 &param) 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 &timestamp_ms)
Writes a log message to the file.
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 &param) const override
Retrieves a floating-point parameter from the logger.
Interface for loggers that handle log message output.
Definition ILogger.hpp:25
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.
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.
std::string utf8_to_ansi(const std::string &utf8)
Converts a UTF-8 string to an ANSI string (Windows-specific).
void create_directories(const std::string &path)
Creates directories recursively for the given path using C++17 std::filesystem.
LoggerParam
Enumeration for different logger parameters that can be retrieved.
Definition Enums.hpp:46
@ TimeSinceLastLog
The time elapsed since the last log in seconds.
Definition Enums.hpp:50
@ LastLogTimestamp
The timestamp of the last log.
Definition Enums.hpp:49
@ LastFileName
The name of the last file written to.
Definition Enums.hpp:47
@ LastFilePath
The full path of the last file written to.
Definition Enums.hpp:48
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.
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.
Definition LogRecord.hpp:13
const int64_t timestamp_ms
Timestamp in milliseconds.
Definition LogRecord.hpp:15