1
2
3
4
5
6 #include <soulng/util/Log.hpp>
7 #include <soulng/util/TextUtils.hpp>
8 #include <soulng/util/Unicode.hpp>
9 #include <iostream>
10 #include <mutex>
11 #include <list>
12 #include <condition_variable>
13 #include <thread>
14 #include <chrono>
15 #include <atomic>
16
17 namespace soulng { namespace util {
18
19 using namespace soulng::unicode;
20
21 std::mutex logMutex;
22 LogMode logMode = LogMode::console;
23 bool endLog = false;
24 std::list<std::string> log;
25 std::condition_variable messageEnqueuedOrEndLog;
26
27 void SetLogMode(LogMode mode)
28 {
29 logMode = mode;
30 }
31
32 void StartLog()
33 {
34 endLog = false;
35 }
36
37 void EndLog()
38 {
39 for (int i = 0; i < 10; ++i)
40 {
41 if (!log.empty())
42 {
43 messageEnqueuedOrEndLog.notify_one();
44 std::this_thread::sleep_for(std::chrono::milliseconds({500 }));
45 }
46 else
47 {
48 break;
49 }
50 }
51 endLog = true;
52 messageEnqueuedOrEndLog.notify_one();
53 }
54
55 void LogMessage(int logStreamId, const std::string& message)
56 {
57 std::lock_guard<std::mutex> lock(logMutex);
58 if (logMode == LogMode::console)
59 {
60 if (logStreamId == -1)
61 {
62 std::cout << message << std::endl;
63 }
64 else
65 {
66 std::cout << Format(std::to_string(logStreamId), 2, FormatWidth::min, FormatJustify::right, '0') << ">" << message << std::endl;
67 }
68 }
69 else if (logMode == LogMode::queue)
70 {
71 if (logStreamId == -1)
72 {
73 log.push_back(message);
74 }
75 else
76 {
77 log.push_back(Format(std::to_string(logStreamId), 2, FormatWidth::min, FormatJustify::right, '0') + ">" + message);
78 }
79 messageEnqueuedOrEndLog.notify_one();
80 }
81 }
82
83 void LogMessage(int logStreamId, const std::string& message, int indent)
84 {
85 LogMessage(logStreamId, std::string(indent, ' ') + message);
86 }
87
88 std::string logMessage;
89
90 int WaitForLogMessage()
91 {
92 std::unique_lock<std::mutex> lock(logMutex);
93 messageEnqueuedOrEndLog.wait(lock, []{ return !log.empty() || endLog; });
94 if (!log.empty())
95 {
96 logMessage = log.front();
97 log.pop_front();
98 return logMessage.length();
99 }
100 else
101 {
102 return -1;
103 }
104 }
105
106 int FetchLogMessage(char16_t* buf, int size)
107 {
108 std::u16string utf16LogMessage = ToUtf16(logMessage);
109 if (size <= utf16LogMessage.length())
110 {
111 return -1;
112 }
113 else
114 {
115 int n = utf16LogMessage.length();
116 for (int i = 0; i < n; ++i)
117 {
118 char16_t c = utf16LogMessage[i];
119 buf[i] = c;
120 }
121 buf[n] = u'\0';
122 return n;
123 }
124 }
125
126 std::string FetchLogMessage(bool& endOfLog, int timeoutMs, bool& timeout)
127 {
128 endOfLog = false;
129 std::unique_lock<std::mutex> lock(logMutex);
130 if (timeoutMs)
131 {
132 if (!messageEnqueuedOrEndLog.wait_for(lock, std::chrono::milliseconds({timeoutMs }) [] { return !log.empty() || endLog; }))
133 {
134 timeout = true;
135 return std::string();
136 }
137 }
138 else
139 {
140 messageEnqueuedOrEndLog.wait(lock, [] { return !log.empty() || endLog; });
141 }
142 if (!log.empty())
143 {
144 logMessage = log.front();
145 log.pop_front();
146 return logMessage;
147 }
148 endOfLog = true;
149 return std::string();
150 }
151
152 } }