Branch data Line data Source code
1 : : #ifndef LOGGER_H
2 : : #define LOGGER_H
3 : :
4 : : #include <string>
5 : : #include <fstream>
6 : : #include <mutex>
7 : : #include <memory>
8 : : #include <iostream>
9 : : #include <sstream>
10 : : #include <iomanip>
11 : : #include <chrono>
12 : : #include <cstdarg>
13 : :
14 : : // Simple synchronous logger that flushes every line for crash debugging
15 : : class Logger {
16 : : public:
17 : 12446 : static Logger& Get() {
18 [ + + + - : 12446 : static Logger instance;
+ - - - ]
19 : 12446 : return instance;
20 : : }
21 : :
22 : 9 : void Init(const std::string& filename) {
23 [ + - ]: 9 : std::lock_guard<std::mutex> lock(m_mutex);
24 [ + - ]: 9 : m_filename = filename;
25 [ + - ]: 9 : m_file.open(m_filename, std::ios::out | std::ios::trunc);
26 [ + - ]: 9 : if (m_file.is_open()) {
27 : 9 : m_initialized = true;
28 [ + - + - : 18 : _LogNoLock("Logger Initialized. Version: " + std::string(LMUFFB_VERSION));
+ - ]
29 : : }
30 : 9 : }
31 : :
32 : 12437 : void Log(const char* fmt, ...) {
33 [ + + ]: 12437 : if (!m_initialized) return;
34 : :
35 : : char buffer[1024];
36 : : va_list args;
37 : 34 : va_start(args, fmt);
38 : 34 : vsnprintf(buffer, sizeof(buffer), fmt, args);
39 : 34 : va_end(args);
40 : :
41 [ + - ]: 34 : std::string message(buffer);
42 : :
43 [ + - ]: 34 : std::lock_guard<std::mutex> lock(m_mutex);
44 [ + - ]: 34 : _LogNoLock(message);
45 : 34 : }
46 : :
47 : : // Helper for std::string
48 : 2 : void LogStr(const std::string& msg) {
49 : 2 : Log("%s", msg.c_str());
50 : 2 : }
51 : :
52 : : // Helper for error logging with GetLastError()
53 : 2 : void LogWin32Error(const char* context, unsigned long errorCode) {
54 : 2 : Log("Error in %s: Code %lu", context, errorCode);
55 : 2 : }
56 : :
57 : : private:
58 [ + - ]: 1 : Logger() {}
59 : 1 : ~Logger() noexcept {
60 : : try {
61 [ + - ]: 1 : if (m_file.is_open()) {
62 [ + - ]: 1 : m_file << "Logger Shutdown.\n";
63 [ + - ]: 1 : m_file.close();
64 : : }
65 : 0 : } catch (...) {
66 : : // Destructor must not throw
67 : 0 : }
68 : 1 : }
69 : :
70 : 43 : void _LogNoLock(const std::string& message) {
71 [ - + ]: 43 : if (!m_file.is_open()) return;
72 : :
73 : : // Timestamp
74 : 43 : auto now = std::chrono::system_clock::now();
75 : 43 : auto in_time_t = std::chrono::system_clock::to_time_t(now);
76 : : std::tm time_info;
77 : : #ifdef _WIN32
78 : : localtime_s(&time_info, &in_time_t);
79 : : #else
80 : 43 : localtime_r(&in_time_t, &time_info);
81 : : #endif
82 : :
83 [ + - + - : 43 : m_file << "[" << std::put_time(&time_info, "%H:%M:%S") << "] " << message << "\n";
+ - + - +
- ]
84 [ + - ]: 43 : m_file.flush(); // Critical for crash debugging
85 : :
86 : : // Also print to console for consistency
87 [ + - + - : 43 : std::cout << "[Log] " << message << std::endl;
+ - ]
88 : : }
89 : :
90 : : std::string m_filename;
91 : : std::ofstream m_file;
92 : : std::mutex m_mutex;
93 : : bool m_initialized = false;
94 : : };
95 : :
96 : : #endif // LOGGER_H
|