VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
Log.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <format>
5#include <functional>
6#include <string>
7#include <string_view>
8
9namespace VoltMod
10{
11
12enum class LogLevel : uint8_t
13{
14 Info,
15 Warn,
16 Error
17};
18
19} // namespace VoltMod
20
21namespace VoltMod::Log
22{
23
24/**
25 * @brief Where log lines end up.
26 *
27 * Invoked on the game thread only. @p message borrows the caller's storage for the duration of
28 * the call, so a handler that keeps a line must copy it.
29 */
30using Handler = std::function<void(LogLevel level, std::string_view message)>;
31
32/**
33 * Install the process-wide handler and record the calling thread as the game thread.
34 *
35 * Set once per load cycle by the plugin module, before anything else logs. A file-static rather
36 * than an injected service because logging must work from code that holds no runtime at all -
37 * static initializers, engine trampolines, and worker threads.
38 */
40
41/** True while a handler is installed. The gate the formatting helpers below check. */
42bool Enabled();
43
44/**
45 * Drop lines below @p level.
46 *
47 * The host decides what each plugin prints, and the SDK reads that back once a frame. Set here
48 * rather than checked per line so the formatting helpers can skip the whole `std::format` call.
49 */
51
52/** The level set by @ref SetMinimumLevel; @ref LogLevel::Info until one is. */
54
55/** Whether a line at @p level would be printed at all. */
56inline bool Wanted(LogLevel level)
57{
58 return Enabled() && level >= MinimumLevel();
59}
60
61/**
62 * Route one formatted line to the handler.
63 *
64 * The console handler reaches tier0's ConColorMsg/Msg, which is game-thread-only, but the
65 * database and HTTP workers log too. A line raised off the installing thread is queued instead
66 * and replayed by @ref DeliverPending, so worker diagnostics still reach the console without a
67 * worker ever touching the engine.
68 */
69void Emit(LogLevel level, std::string message);
70
71/** Replay lines queued from worker threads. Game thread only; `Runtime::OnGameFrame` calls it. */
72void DeliverPending();
73
74// Formatting is skipped entirely without a handler, and for a level the host does not want:
75// diagnostic logging behind a debug gate should cost nothing before SetHandler, after unload, and
76// while the plugin is silenced.
77
78template <typename... Args>
79void Info(std::format_string<Args...> fmt, Args&&... args)
80{
82 {
83 Emit(LogLevel::Info, std::format(fmt, std::forward<Args>(args)...));
84 }
85}
86
87template <typename... Args>
88void Warn(std::format_string<Args...> fmt, Args&&... args)
89{
91 {
92 Emit(LogLevel::Warn, std::format(fmt, std::forward<Args>(args)...));
93 }
94}
95
96template <typename... Args>
97void Error(std::format_string<Args...> fmt, Args&&... args)
98{
100 {
101 Emit(LogLevel::Error, std::format(fmt, std::forward<Args>(args)...));
102 }
103}
104
105} // namespace VoltMod::Log
bool Enabled()
Definition Logger.cpp:32
std::function< void(LogLevel level, std::string_view message)> Handler
Where log lines end up.
Definition Log.hpp:30
LogLevel MinimumLevel()
Definition Logger.cpp:42
bool Wanted(LogLevel level)
Definition Log.hpp:56
void DeliverPending()
Definition Logger.cpp:69
void Emit(LogLevel level, std::string message)
Definition Logger.cpp:47
void SetHandler(Handler handler)
Definition Logger.cpp:26
void SetMinimumLevel(LogLevel level)
Definition Logger.cpp:37
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
LogLevel
Definition Log.hpp:13
One failure: a code to branch on, text for the log, and an optional translation key.
Definition Result.hpp:42