-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathLogger.cpp
More file actions
138 lines (112 loc) · 2.97 KB
/
Copy pathLogger.cpp
File metadata and controls
138 lines (112 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include "Logger.h"
#include <chrono>
#include <ctime>
#include <filesystem>
#include <iomanip>
#include <sstream>
#include <vector>
#include <Windows.h>
Logger& Logger::instance()
{
static Logger s_instance;
return s_instance;
}
void Logger::init(const std::wstring& filePath)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_path = filePath;
// Ensure directory exists
if (!m_path.empty())
{
try
{
std::filesystem::path p(m_path);
std::filesystem::create_directories(p.parent_path());
}
catch (...)
{
// Best effort; failure will surface when opening the stream
}
}
m_initialized = true;
ensureOpenUnlocked();
}
bool Logger::ensureOpenUnlocked()
{
if (!m_initialized)
return false;
if (!m_stream.is_open())
{
m_stream.open(m_path, std::ios::out | std::ios::app);
}
return m_stream.is_open();
}
void Logger::log(LogLevel level, const std::string& message)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!ensureOpenUnlocked())
return;
writeLineUnlocked(level, message);
}
void Logger::log(LogLevel level, const std::wstring& message)
{
log(level, narrow(message));
}
void Logger::logInfo(const std::string& message)
{
log(LogLevel::Info, message);
}
void Logger::logWarning(const std::string& message)
{
log(LogLevel::Warning, message);
}
void Logger::logError(const std::string& message)
{
log(LogLevel::Error, message);
}
void Logger::writeLineUnlocked(LogLevel level, const std::string& message)
{
if (!m_stream.is_open())
return;
m_stream << makeTimestamp() << " [" << levelToString(level) << "] " << message << std::endl;
}
void Logger::flush()
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_stream.is_open())
m_stream.flush();
}
std::string Logger::levelToString(LogLevel level)
{
switch (level)
{
case LogLevel::Info: return "INFO";
case LogLevel::Warning: return "WARN";
case LogLevel::Error: return "ERROR";
default: return "LOG";
}
}
std::string Logger::makeTimestamp()
{
using namespace std::chrono;
auto now = system_clock::now();
auto timeT = system_clock::to_time_t(now);
auto tm = std::tm{};
localtime_s(&tm, &timeT);
auto ms = duration_cast<milliseconds>(now.time_since_epoch()) % 1000;
std::ostringstream oss;
oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
<< '.' << std::setw(3) << std::setfill('0') << ms.count();
return oss.str();
}
std::string Logger::narrow(const std::wstring& wide)
{
if (wide.empty())
return {};
int required = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), (int)wide.size(), nullptr, 0, nullptr, nullptr);
if (required <= 0)
return {};
std::vector<char> buffer(required);
WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), (int)wide.size(), buffer.data(), required, nullptr, nullptr);
return std::string(buffer.begin(), buffer.end());
}