aboutsummaryrefslogtreecommitdiff
path: root/src/brussel.common/Log.hpp
blob: aeba984c13f9e9cb9b7f926c91842d2914744bfd (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
#pragma once

#include "RingBuffer.hpp"

#include <fmt/format.h>
#include <chrono>
#include <source_location>
#include <string_view>

// NOTE: we keep this on one line so std::soruce_location reports the correct information
#define GENERIC_LOG(lvl, fmtString, ...) Log::Add(Log::Message{ .level = lvl, .time = std::chrono::system_clock::now(), .srcLoc = std::source_location::current(), .text = fmt::format(fmtString __VA_OPT__(, ) __VA_ARGS__) })

#define LOG_DEBUG(...) GENERIC_LOG(Log::MessageLevel::Debug, __VA_ARGS__)
#define LOG_INFO(...) GENERIC_LOG(Log::MessageLevel::Info, __VA_ARGS__)
#define LOG_WARNING(...) GENERIC_LOG(Log::MessageLevel::Warning, __VA_ARGS__)
#define LOG_ERROR(...) GENERIC_LOG(Log::MessageLevel::Error, __VA_ARGS__)

namespace Log {
enum class MessageLevel {
	Debug,
	Info,
	Warning,
	Error,
};

struct Message {
	MessageLevel level;
	std::chrono::time_point<std::chrono::system_clock> time;
	std::source_location srcLoc;
	std::string text;
};

/// A mRing buffer of log messages for programmatic inspection at runtime.
struct MessageBuffer {
	RingBuffer<Message> messages;
};

/// Unique ID identifying a currently registered MessageBuffer.
using MessageBufferId = int;

MessageBufferId RegisterBuffer(MessageBuffer& buffer);
void UnregisterBuffer(MessageBufferId id);
MessageBuffer* GetBuffer(MessageBufferId id);
void DumpRegisteredBuffers();

extern bool gPrintToStdOut;
#if BRUSSEL_DEV_ENV
// NOTE: initialized in main.cpp
extern MessageBuffer gDefaultBuffer;
extern MessageBufferId gDefaultBufferId;
#endif

// TODO improve this interface: don't copy std::string when there is in fact no MessageBuffer registered
void Add(const Message& msg);
} // namespace Log