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
|
#include "Log.hpp"
#include "Macros.hpp"
#include <robin_hood.h>
#include <algorithm>
#include <cstdio>
namespace ProjectBrussel_UNITY_ID {
using namespace Log;
const char* MapMessageLevelToString(MessageLevel level) {
switch (level) {
using enum MessageLevel;
case Debug: return "DEBUG";
case Info: return "INFO";
case Warning: return "WARN";
case Error: return "ERROR";
default: UNREACHABLE;
}
}
void PrintMessage(const Message& msg) {
using namespace std::chrono;
auto t = system_clock::to_time_t(msg.time);
char timeStr[128];
strftime(timeStr, sizeof(timeStr), "%H:%M:%S", localtime(&t));
printf("[%s][%s][%s:%u] %.*s\n",
MapMessageLevelToString(msg.level),
timeStr,
msg.srcLoc.function_name(),
msg.srcLoc.line(),
PRINTF_STRING_VIEW(msg.text));
}
MessageBufferId gNextBufferId = 0;
robin_hood::unordered_map<MessageBufferId, MessageBuffer*> gBuffers;
} // namespace ProjectBrussel_UNITY_ID
namespace Log {
bool gPrintToStdOut = true;
#if BRUSSEL_DEV_ENV
MessageBuffer gDefaultBuffer;
MessageBufferId gDefaultBufferId;
#endif
} // namespace Log
Log::MessageBufferId Log::RegisterBuffer(MessageBuffer& buffer) {
using namespace ProjectBrussel_UNITY_ID;
auto id = gNextBufferId++;
gBuffers.try_emplace(id, &buffer);
return id;
}
void Log::UnregisterBuffer(MessageBufferId id) {
using namespace ProjectBrussel_UNITY_ID;
gBuffers.erase(id);
}
Log::MessageBuffer* Log::GetBuffer(MessageBufferId id) {
using namespace ProjectBrussel_UNITY_ID;
auto iter = gBuffers.find(id);
if (iter != gBuffers.end()) {
return iter->second;
} else {
return nullptr;
}
}
void Log::DumpRegisteredBuffers() {
using namespace ProjectBrussel_UNITY_ID;
puts("================ BEGIN LOG BUFFER DUMP ================");
for (const auto& [id, buffer] : gBuffers) {
printf("Buffer #%d at %p\n", id, buffer);
printf("Buffer size: %zu\n", buffer->messages.capacity());
bool needsWrapAround = buffer->messages.GetHeadIdx() >= buffer->messages.GetTailIdx();
if (needsWrapAround) {
printf("Fill size: %zu in [%zu,%zu) and [0,%zu)\n",
buffer->messages.size(),
// First chunk: [begin,end)
buffer->messages.GetHeadIdx(),
buffer->messages.capacity(),
// Second chunk: [0,end)
buffer->messages.GetTailIdx());
} else {
printf("Fill size: %zu in [%zu,%zu)\n",
buffer->messages.size(),
// [begin,end)
buffer->messages.GetHeadIdx(),
buffer->messages.GetTailIdx());
}
for (const auto& msg : buffer->messages) {
// Indent log messages in this buffer
printf("\t");
PrintMessage(msg);
}
}
puts("================ END LOG BUFFER DUMP ================");
}
void Log::Add(const Message& msg) {
using namespace ProjectBrussel_UNITY_ID;
if (gPrintToStdOut) {
PrintMessage(msg);
}
for (auto& [_, buffer] : gBuffers) {
buffer->messages.push_back(msg);
}
}
|