aboutsummaryrefslogtreecommitdiff
path: root/src/brussel.common/Log.cpp
blob: 83d81e97e04f1658af5dd3df79682c94b1fbd184 (plain)
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);
	}
}