1
+ #pragma once
2
+
3
+ #include < fstream>
4
+ #include < atomic>
5
+ #include < thread>
6
+ #include < mutex>
7
+ #include < utility>
8
+ #include < filesystem>
9
+ #include < sstream>
10
+
11
+ #include " MemoryBoundedQueue.h"
12
+
13
+ class FileLogger {
14
+ private:
15
+ MemoryBoundedQueue<std::string> &queue_;
16
+ std::ofstream file_stream_;
17
+ std::atomic<bool > running_ = true ;
18
+ std::atomic<bool > wait_ = false ;
19
+ std::thread worker_;
20
+ std::mutex mtx_;
21
+ std::string filename_;
22
+ const std::chrono::milliseconds flush_interval_ = std::chrono::milliseconds(100 );
23
+ const unsigned long max_file_size_;
24
+ bool stopWorker = false ;
25
+
26
+ // Generate a filename based on the current date and time
27
+ static std::string getFormattedFilename () {
28
+ // Get current time as system_clock time_point
29
+ auto now = std::chrono::system_clock::now ();
30
+ // Convert to time_t for compatibility with C time functions
31
+ auto now_c = std::chrono::system_clock::to_time_t (now);
32
+ // Convert to tm struct for use with put_time
33
+ struct tm now_tm{};
34
+ localtime_s (&now_tm, &now_c);
35
+
36
+ // Use ostringstream to format filename
37
+ std::ostringstream oss;
38
+ oss << std::put_time (&now_tm, " syslog_%Y_%m_%d_%H_%M_%S.txt" );
39
+
40
+ return oss.str ();
41
+ }
42
+
43
+ // Open a new log file with the current timestamp
44
+ void openNewLogFile () {
45
+ if (file_stream_.is_open ()) {
46
+ file_stream_.close ();
47
+ }
48
+ filename_ = getFormattedFilename ();
49
+ file_stream_.open (filename_, std::ios::app);
50
+ }
51
+
52
+ // Check the size of the current log file and rotate if necessary
53
+ void checkAndRotateFile () {
54
+ if (std::filesystem::file_size (filename_) >= max_file_size_) {
55
+ openNewLogFile ();
56
+ }
57
+ }
58
+
59
+ void backgroundScreenFlush () {
60
+ while (!stopWorker) {
61
+ std::this_thread::sleep_for (flush_interval_);
62
+ std::lock_guard<std::mutex> lock (mtx_);
63
+ file_stream_.flush ();
64
+ }
65
+ }
66
+
67
+ public:
68
+ FileLogger (MemoryBoundedQueue<std::string> &q, unsigned long file_size)
69
+ : filename_(std::move(getFormattedFilename())),
70
+ max_file_size_(file_size),
71
+ queue_(q) {
72
+ worker_ = std::thread (&::FileLogger::backgroundScreenFlush, this );
73
+ }
74
+
75
+ ~FileLogger () {
76
+ stopWorker = true ;
77
+ worker_.join ();
78
+ if (file_stream_.is_open ()) {
79
+ file_stream_.close ();
80
+ }
81
+ }
82
+
83
+ void run () {
84
+ file_stream_.open (filename_, std::ios::app);
85
+ unsigned int count = 0 ;
86
+ while (running_) {
87
+ std::string log = queue_.pop ();
88
+ std::lock_guard<std::mutex> lock (mtx_);
89
+ file_stream_ << log << std::endl;
90
+ checkAndRotateFile ();
91
+ }
92
+ file_stream_.flush (); // in case wait_ is used and takes time
93
+ if (wait_) {
94
+ while (!queue_.empty ()) {
95
+ std::string log = queue_.pop ();
96
+ std::lock_guard<std::mutex> lock (mtx_);
97
+ file_stream_ << log << std::endl;
98
+ checkAndRotateFile ();
99
+ }
100
+ file_stream_.flush ();
101
+ }
102
+ }
103
+
104
+ void stop () {
105
+ wait_ = false ;
106
+ running_ = false ;
107
+ }
108
+
109
+ void stopWaitFinished () {
110
+ wait_ = true ;
111
+ running_ = false ;
112
+ }
113
+ };
0 commit comments