TachyonUI 0.1.0
High-performance UI for building tools.
Loading...
Searching...
No Matches
gui_logging.h
Go to the documentation of this file.
1#pragma once
2
3// Structured logging (engine design docs 02 and 28): each message is a fixed-size
4// record - category, severity, a static message template with `{}` placeholders and
5// up to kMaxLogArgs typed arguments. Formatting happens lazily, at the sink.
6//
7// Records land in an in-memory ring of recent history (read by the editor's console,
8// newest-last, with a sequence number for incremental reads) and are handed to every
9// registered sink. A built-in console sink mirrors them to stdout / stderr and, on
10// Windows, the debugger output.
11//
12// Emitting never allocates: text arguments are copied into the record's own fixed
13// buffer (truncated if they don't fit), so dynamic strings such as file paths are safe
14// to pass. The message template and category name must be static strings.
15
16#include <stdint.h>
17#include <span>
18#include <string_view>
19#include <type_traits>
20
21#include <gui_core/gui_hash.h>
22
24{
27
28 enum class LogSeverity : uint8_t { Trace = 0, Debug, Info, Warning, Error, Critical };
29
30 const char* LogSeverityName(LogSeverity severity);
31
35 {
36 uint64_t id = 0;
37 std::string_view name;
38 };
39
41 constexpr LogCategory MakeLogCategory(std::string_view staticName)
42 {
43 return { Hash::CalculateConst(staticName), staticName };
44 }
45
48 struct LogArg
49 {
51 enum class Kind : uint8_t { None = 0, Int, Uint, Float, Text };
52
54 union
55 {
56 int64_t i = 0;
57 uint64_t u;
58 double f;
59 };
60 std::string_view text;
61 uint16_t textOffset = 0;
62 uint16_t textLength = 0;
63 };
64
65 template<typename T>
66 LogArg MakeLogArg(const T& value)
67 {
68 LogArg arg;
69 if constexpr (std::is_same_v<T, bool>)
70 {
72 arg.text = value ? "true" : "false";
73 }
74 else if constexpr (std::is_enum_v<T>)
75 {
77 arg.i = static_cast<int64_t>(value);
78 }
79 else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
80 {
82 arg.i = value;
83 }
84 else if constexpr (std::is_integral_v<T>)
85 {
87 arg.u = value;
88 }
89 else if constexpr (std::is_floating_point_v<T>)
90 {
92 arg.f = static_cast<double>(value);
93 }
94 else
95 {
96 static_assert(std::is_convertible_v<const T&, std::string_view>, "unsupported log argument type");
98 arg.text = std::string_view(value);
99 }
100 return arg;
101 }
102
103 inline constexpr int kMaxLogArgs = 4;
104 inline constexpr int kLogTextCapacity = 384;
105 inline constexpr int kLogRingCapacity = 1024;
106 inline constexpr int kMaxLogSinks = 8;
107
111 {
112 uint64_t sequence = 0;
113 int64_t timestampNanos = 0;
114 uint64_t threadId = 0;
117 std::string_view messageTemplate;
118 const char* file = "";
119 uint32_t line = 0;
120 uint8_t argCount = 0;
123 };
124
125 std::string_view LogArgText(const LogRecord& record, const LogArg& arg);
126
129 size_t FormatLogMessage(const LogRecord& record, std::span<char> out);
130
136
138 void SetLogConsoleOutput(bool enabled);
139
141 using LogSinkFn = void (*)(const LogRecord& record, void* context);
144 bool AddLogSink(LogSinkFn sink, void* context);
146 void RemoveLogSink(LogSinkFn sink, void* context);
147
149 void LogMessage(LogCategory category, LogSeverity severity, std::string_view messageTemplate,
150 std::span<const LogArg> args, const char* file = "", uint32_t line = 0);
151
156 void ReportMisuse(LogCategory category, const char* message);
159
162
165 uint32_t CopyRecentLogRecords(std::span<LogRecord> out);
166
169 template<typename... Args>
170 void Log(LogCategory category, LogSeverity severity, const char* file, uint32_t line,
171 std::string_view messageTemplate, const Args&... args)
172 {
173 static_assert(sizeof...(Args) <= kMaxLogArgs, "too many log arguments");
174 if (severity < GetMinimumLogSeverity())
175 return;
176 const LogArg packed[sizeof...(Args) + 1] = { MakeLogArg(args)..., LogArg{} };
177 LogMessage(category, severity, messageTemplate, std::span<const LogArg>(packed, sizeof...(Args)), file, line);
178 }
179
180}
181
182#define TACHYON_LOG_TRACE(category, ...) ::tachyon::Diagnostics::Log(category, ::tachyon::Diagnostics::LogSeverity::Trace, __FILE__, __LINE__, __VA_ARGS__)
183#define TACHYON_LOG_DEBUG(category, ...) ::tachyon::Diagnostics::Log(category, ::tachyon::Diagnostics::LogSeverity::Debug, __FILE__, __LINE__, __VA_ARGS__)
184#define TACHYON_LOG_INFO(category, ...) ::tachyon::Diagnostics::Log(category, ::tachyon::Diagnostics::LogSeverity::Info, __FILE__, __LINE__, __VA_ARGS__)
185#define TACHYON_LOG_WARNING(category, ...) ::tachyon::Diagnostics::Log(category, ::tachyon::Diagnostics::LogSeverity::Warning, __FILE__, __LINE__, __VA_ARGS__)
186#define TACHYON_LOG_ERROR(category, ...) ::tachyon::Diagnostics::Log(category, ::tachyon::Diagnostics::LogSeverity::Error, __FILE__, __LINE__, __VA_ARGS__)
187#define TACHYON_LOG_CRITICAL(category, ...) ::tachyon::Diagnostics::Log(category, ::tachyon::Diagnostics::LogSeverity::Critical, __FILE__, __LINE__, __VA_ARGS__)
uint32_t CopyRecentLogRecords(std::span< LogRecord > out)
Copies up to out.size() of the most recent records, oldest first.
constexpr int kLogRingCapacity
Definition gui_logging.h:105
void SetMinimumLogSeverity(LogSeverity severity)
Records below the minimum severity are dropped before any work is done.
void RemoveLogSink(LogSinkFn sink, void *context)
Unregisters a sink added with the same sink and context. [MainThread].
bool AddLogSink(LogSinkFn sink, void *context)
Registers sink, called with every record and context.
void SetLogConsoleOutput(bool enabled)
Turns the built-in stdout/stderr/debugger sink on or off (on by default). [AnyThread].
void(*)(const LogRecord &record, void *context) LogSinkFn
A log sink. Sinks run on the emitting thread, under the logger's lock.
Definition gui_logging.h:141
void LogMessage(LogCategory category, LogSeverity severity, std::string_view messageTemplate, std::span< const LogArg > args, const char *file="", uint32_t line=0)
Emits one record. Prefer the TACHYON_LOG_* macros, which add the source location. [AnyThread].
constexpr LogCategory MakeLogCategory(std::string_view staticName)
A category named staticName, which must be a static string.
Definition gui_logging.h:41
std::string_view LogArgText(const LogRecord &record, const LogArg &arg)
constexpr int kMaxLogArgs
Definition gui_logging.h:103
void ReportMisuse(LogCategory category, const char *message)
API misuse (an unbalanced Begin/End, a call outside its frame, ...) is reported, not fatal: the calle...
const char * LogSeverityName(LogSeverity severity)
LogSeverity
Definition gui_logging.h:28
void ResetMisuseReports()
Lets every misuse be reported again (tests). [AnyThread].
size_t FormatLogMessage(const LogRecord &record, std::span< char > out)
Writes the template with its arguments substituted, NUL-terminated and truncated to out.
constexpr int kMaxLogSinks
Definition gui_logging.h:106
LogSeverity GetMinimumLogSeverity()
Records below the minimum severity are dropped before any work is done.
constexpr int kLogTextCapacity
bytes shared by a record's text arguments
Definition gui_logging.h:104
uint64_t LatestLogSequence()
Sequence number of the newest record (0 before the first). [AnyThread].
void Log(LogCategory category, LogSeverity severity, const char *file, uint32_t line, std::string_view messageTemplate, const Args &... args)
Emits a record with args (at most kMaxLogArgs) for the {} in messageTemplate; what the TACHYON_LOG_* ...
Definition gui_logging.h:170
LogArg MakeLogArg(const T &value)
Definition gui_logging.h:66
@ Warning
Definition gui_logging.h:28
@ Critical
Definition gui_logging.h:28
@ Info
Definition gui_logging.h:28
@ Debug
Definition gui_logging.h:28
@ Trace
Definition gui_logging.h:28
@ None
Definition gui_element_flags.h:19
@ Text
dropped: text, in data
Definition gui_input_enums.h:69
Definition gui_logging.h:24
constexpr uint64_t CalculateConst(std::string_view str, uint64_t hash=Basis)
FNV-1a hash of str, usable at compile time; hash continues an earlier hash.
Definition gui_hash.h:18
One argument.
Definition gui_logging.h:49
Kind kind
Picks i, u, f or the text.
Definition gui_logging.h:53
uint16_t textLength
record only: the text's length in bytes
Definition gui_logging.h:62
Kind
Which value the argument holds.
Definition gui_logging.h:51
@ Int
Definition gui_logging.h:51
@ Float
Definition gui_logging.h:51
@ None
Definition gui_logging.h:51
@ Text
Definition gui_logging.h:51
@ Uint
Definition gui_logging.h:51
uint16_t textOffset
record only: where the text starts in LogRecord::text
Definition gui_logging.h:61
std::string_view text
Kind::Text, while passed to LogMessage.
Definition gui_logging.h:60
A subsystem's log category.
Definition gui_logging.h:35
std::string_view name
Shown with each record.
Definition gui_logging.h:37
One message as sinks and CopyRecentLogRecords see it.
Definition gui_logging.h:111
LogCategory category
Where it comes from.
Definition gui_logging.h:115
const char * file
Source file of the call (FILE).
Definition gui_logging.h:118
uint64_t sequence
1-based, increases by one per record
Definition gui_logging.h:112
LogArg args[kMaxLogArgs]
The arguments; read text ones with LogArgText.
Definition gui_logging.h:121
int64_t timestampNanos
steady clock, see SteadyClockNowNanos
Definition gui_logging.h:113
uint8_t argCount
How many of args are used.
Definition gui_logging.h:120
LogSeverity severity
How serious it is.
Definition gui_logging.h:116
uint32_t line
Source line of the call.
Definition gui_logging.h:119
char text[kLogTextCapacity]
The text arguments' bytes.
Definition gui_logging.h:122
std::string_view messageTemplate
Static, with a {} per argument.
Definition gui_logging.h:117
uint64_t threadId
Hash of the emitting thread's std::thread::id.
Definition gui_logging.h:114
A failure: its category and a human-readable message.
Definition gui_result.h:26