Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/common/log.h
7400 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#pragma once
5
6
#include "log_channels.h"
7
#include "types.h"
8
9
#include "fmt/base.h"
10
11
#include <array>
12
#include <cinttypes>
13
#include <cstdarg>
14
#include <mutex>
15
#include <string_view>
16
17
namespace Log {
18
enum class Level : u32
19
{
20
None, // Silences all log traffic
21
Error,
22
Warning,
23
Info,
24
Verbose,
25
Dev,
26
Debug,
27
Trace,
28
29
MaxCount
30
};
31
32
enum class Color : u32
33
{
34
Default,
35
Black,
36
Red,
37
Green,
38
Blue,
39
Magenta,
40
Orange,
41
Cyan,
42
Yellow,
43
White,
44
StrongBlack,
45
StrongRed,
46
StrongGreen,
47
StrongBlue,
48
StrongMagenta,
49
StrongOrange,
50
StrongCyan,
51
StrongYellow,
52
StrongWhite,
53
54
MaxCount
55
};
56
57
enum class Channel : u32
58
{
59
#define LOG_CHANNEL_ENUM(X) X,
60
ENUMERATE_LOG_CHANNELS(LOG_CHANNEL_ENUM)
61
#undef LOG_CHANNEL_ENUM
62
63
MaxCount
64
};
65
66
// Default log level.
67
static constexpr Log::Level DEFAULT_LOG_LEVEL = Log::Level::Info;
68
69
// Packs a level and channel into one 16-bit number.
70
using MessageCategory = u32;
71
[[maybe_unused]] ALWAYS_INLINE constexpr u32 PackCategory(Channel channel, Level level, Color color)
72
{
73
return ((static_cast<MessageCategory>(color) << 10) | (static_cast<MessageCategory>(channel) << 3) |
74
static_cast<MessageCategory>(level));
75
}
76
[[maybe_unused]] ALWAYS_INLINE constexpr Color UnpackColor(MessageCategory cat)
77
{
78
return static_cast<Color>((cat >> 10) & 0x1f);
79
}
80
[[maybe_unused]] ALWAYS_INLINE constexpr Channel UnpackChannel(MessageCategory cat)
81
{
82
return static_cast<Channel>((cat >> 3) & 0x7f);
83
}
84
[[maybe_unused]] ALWAYS_INLINE constexpr Level UnpackLevel(MessageCategory cat)
85
{
86
return static_cast<Level>(cat & 0x7);
87
}
88
89
// log message callback type
90
using CallbackFunctionType = void (*)(void* pUserParam, MessageCategory category, const char* functionName,
91
std::string_view message);
92
93
// registers a log callback
94
void RegisterCallback(CallbackFunctionType callbackFunction, void* pUserParam);
95
96
// unregisters a log callback
97
void UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam);
98
99
// returns a list of all log channels
100
const std::array<const char*, static_cast<size_t>(Channel::MaxCount)>& GetChannelNames();
101
102
// returns the time in seconds since the start of the process
103
float GetCurrentMessageTime();
104
bool AreConsoleOutputTimestampsEnabled();
105
106
// adds a standard console output
107
bool IsConsoleOutputCurrentlyAvailable();
108
bool IsConsoleOutputEnabled();
109
void SetConsoleOutputParams(bool enabled, bool timestamps = true);
110
111
// adds a debug console output [win32/android only]
112
bool IsDebugOutputEnabled();
113
void SetDebugOutputParams(bool enabled);
114
115
// adds a file output
116
void SetFileOutputParams(bool enabled, const char* filename, bool timestamps = true);
117
118
// Returns the current global filtering level.
119
Level GetLogLevel();
120
121
// Returns true if log messages for the specified log level/filter would not be filtered (and visible).
122
bool IsLogVisible(Level level, Channel channel);
123
124
// Sets global filtering level, messages below this level won't be sent to any of the logging sinks.
125
void SetLogLevel(Level level);
126
127
// Sets global filter, any messages from these channels won't be sent to any of the logging sinks.
128
void SetLogChannelEnabled(Channel channel, bool enabled);
129
130
// Returns the name of the specified log channel.
131
const char* GetChannelName(Channel channel);
132
133
// Returns the default color for a log level.
134
Color GetColorForLevel(Level level);
135
136
// writes a message to the log
137
void Write(MessageCategory cat, std::string_view message);
138
void WriteFuncName(MessageCategory cat, const char* function_name, std::string_view message);
139
void WriteFmtArgs(MessageCategory cat, fmt::string_view fmt, fmt::format_args args);
140
void WriteFuncNameFmtArgs(MessageCategory cat, const char* function_name, fmt::string_view fmt, fmt::format_args args);
141
142
template<typename... T>
143
ALWAYS_INLINE void Write(MessageCategory cat, fmt::format_string<T...> fmt, T&&... args)
144
{
145
WriteFmtArgs(cat, fmt, fmt::make_format_args(args...));
146
}
147
148
template<typename... T>
149
ALWAYS_INLINE void WriteFuncName(MessageCategory cat, const char* function_name, fmt::format_string<T...> fmt,
150
T&&... args)
151
{
152
WriteFuncNameFmtArgs(cat, function_name, fmt, fmt::make_format_args(args...));
153
}
154
155
} // namespace Log
156
157
// log wrappers
158
#define LOG_CHANNEL(name) [[maybe_unused]] static constexpr Log::Channel ___LogChannel___ = Log::Channel::name;
159
160
#define GENERIC_LOG(channel, level, color, ...) \
161
do \
162
{ \
163
if ((level) <= Log::GetLogLevel()) [[unlikely]] \
164
Log::Write(Log::PackCategory((channel), (level), (color)), __VA_ARGS__); \
165
} while (0)
166
167
#define GENERIC_FUNC_LOG(channel, level, color, ...) \
168
do \
169
{ \
170
if ((level) <= Log::GetLogLevel()) [[unlikely]] \
171
Log::WriteFuncName(Log::PackCategory((channel), (level), (color)), __func__, __VA_ARGS__); \
172
} while (0)
173
174
// clang-format off
175
176
#define ERROR_LOG(...) GENERIC_FUNC_LOG(___LogChannel___, Log::Level::Error, Log::Color::Default, __VA_ARGS__)
177
#define WARNING_LOG(...) GENERIC_FUNC_LOG(___LogChannel___, Log::Level::Warning, Log::Color::Default, __VA_ARGS__)
178
#define INFO_LOG(...) GENERIC_LOG(___LogChannel___, Log::Level::Info, Log::Color::Default, __VA_ARGS__)
179
#define VERBOSE_LOG(...) GENERIC_LOG(___LogChannel___, Log::Level::Verbose, Log::Color::Default, __VA_ARGS__)
180
#define DEV_LOG(...) GENERIC_LOG(___LogChannel___, Log::Level::Dev, Log::Color::Default, __VA_ARGS__)
181
182
#if defined(_DEBUG) || defined(_DEVEL)
183
#define DEBUG_LOG(...) GENERIC_LOG(___LogChannel___, Log::Level::Debug, Log::Color::Default, __VA_ARGS__)
184
#define TRACE_LOG(...) GENERIC_LOG(___LogChannel___, Log::Level::Trace, Log::Color::Default, __VA_ARGS__)
185
#else
186
#define DEBUG_LOG(...) do { } while (0)
187
#define TRACE_LOG(...) do { } while (0)
188
#endif
189
190
#define ERROR_COLOR_LOG(color, ...) GENERIC_FUNC_LOG(___LogChannel___, Log::Level::Error, Log::Color::color, __VA_ARGS__)
191
#define WARNING_COLOR_LOG(color, ...) GENERIC_FUNC_LOG(___LogChannel___, Log::Level::Warning, Log::Color::color, __VA_ARGS__)
192
#define INFO_COLOR_LOG(color, ...) GENERIC_LOG(___LogChannel___, Log::Level::Info, Log::Color::color, __VA_ARGS__)
193
#define VERBOSE_COLOR_LOG(color, ...) GENERIC_LOG(___LogChannel___, Log::Level::Verbose, Log::Color::color, __VA_ARGS__)
194
#define DEV_COLOR_LOG(color, ...) GENERIC_LOG(___LogChannel___, Log::Level::Dev, Log::Color::color, __VA_ARGS__)
195
196
#if defined(_DEBUG) || defined(_DEVEL)
197
#define DEBUG_COLOR_LOG(color, ...) GENERIC_LOG(___LogChannel___, Log::Level::Debug, Log::Color::color, __VA_ARGS__)
198
#define TRACE_COLOR_LOG(color, ...) GENERIC_LOG(___LogChannel___, Log::Level::Trace, Log::Color::color, __VA_ARGS__)
199
#else
200
#define DEBUG_COLOR_LOG(color, ...) do { } while (0)
201
#define TRACE_COLOR_LOG(color, ...) do { } while (0)
202
#endif
203
204
// clang-format on
205
206