SuperDex Physics C++ API
Loading...
Searching...
No Matches
log.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
20
21#if MOCHI_PLATFORM_WINDOWS && !defined(__UNREAL__)
22#ifndef NOMINMAX
23#define NOMINMAX
24#endif
25#include <Windows.h>
26#endif // MOCHI_PLATFORM_WINDOWS && !defined(__UNREAL__)
27
28#include <array>
29#include <cstdarg>
30#include <functional>
31#include <mutex>
32#include <string>
33
34namespace superdex {
35
36// Log messages are grouped into channels that can be enabled/disabled
38
39// Macros: Output to the log if the specified channel is enabled.
40// clang-format off
41#define MOCHI_LOG(...) MOCHI_LOG_IMPL(::superdex::LogChannel::Info, __FILE__, __LINE__, __VA_ARGS__)
42#define MOCHI_LOG_VERBOSE(...) MOCHI_LOG_IMPL(::superdex::LogChannel::Verbose, __FILE__, __LINE__, __VA_ARGS__)
43#define MOCHI_LOG_WARNING(...) MOCHI_LOG_IMPL(::superdex::LogChannel::Warning, __FILE__, __LINE__, __VA_ARGS__)
44#define MOCHI_LOG_ERROR(...) MOCHI_LOG_IMPL(::superdex::LogChannel::Error, __FILE__, __LINE__, __VA_ARGS__)
45#define MOCHI_LOG_TO(channel, ...) MOCHI_LOG_IMPL(channel, __FILE__, __LINE__, __VA_ARGS__)
46// clang-format on
47
48// Same but log only the first time.
49#define MOCHI_LOG_ONCE_HELPER(channel, ...) \
50 do { \
51 [[maybe_unused]] static bool logged_##__LINE__ = [&]() { \
52 MOCHI_LOG_IMPL(channel, __FILE__, __LINE__, __VA_ARGS__); \
53 return true; \
54 }(); \
55 } while (0)
56#define MOCHI_LOG_ONCE(...) MOCHI_LOG_ONCE_HELPER(::superdex::LogChannel::Info, __VA_ARGS__)
57#define MOCHI_LOG_VERBOSE_ONCE(...) MOCHI_LOG_ONCE_HELPER(::superdex::LogChannel::Verbose, __VA_ARGS__)
58#define MOCHI_LOG_WARNING_ONCE(...) MOCHI_LOG_ONCE_HELPER(::superdex::LogChannel::Warning, __VA_ARGS__)
59#define MOCHI_LOG_ERROR_ONCE(...) MOCHI_LOG_ONCE_HELPER(::superdex::LogChannel::Error, __VA_ARGS__)
60
61// Return a std::string initialized with printf-style formatting
62[[nodiscard]] std::string Format(char const* format, ...);
63
64// Signature of a logging callback function
65using LogFn = std::function<void(LogChannel, char const* message, char const* file, int line)>;
66
67// Get the current logging function.
68[[nodiscard]] LogFn GetLogCallback();
69
70// Set the logging function to redirect output. Pass LogFn{} to restore default logging.
71void SetLogCallback(LogFn fn);
72
73// Enable or disable log messages on the specified channel
74void EnableLogChannel(LogChannel channel, bool enable);
75
76// Return true if messages on the specified channel should be shown
77[[nodiscard]] bool IsLogChannelEnabled(LogChannel channel);
78
79// Output to the current logging function.
80void Log(LogChannel channel, std::string msg, char const* file, int line, bool newline);
81
82// Ensure that recent logging has been flushed to the output pipe.
83void FlushLog();
84
85//------------------------------------------------------------------------------------------------
86// Implementation Details
87//------------------------------------------------------------------------------------------------
88
89#define MOCHI_LOG_IMPL(channel, file, line, ...) \
90 if (::superdex::IsLogChannelEnabled(channel)) { \
91 ::superdex::Log(channel, ::superdex::Format(__VA_ARGS__), file, line, true); \
92 } else { \
93 }
94
95// Supports Format(__VA_ARGS__) when __VA_ARGS__ is empty
96[[nodiscard]] inline std::string Format() {
97 return {};
98}
99
100[[nodiscard]] inline std::string Format(char const* format, ...) {
101 va_list args1, args2;
102 va_start(args1, format);
103 va_copy(args2, args1);
104 int len = vsnprintf(nullptr, 0, format, args1);
105 std::string str;
106 str.resize((size_t)len); // +1 makes it cheap to append "\n" for logging
107 if (len)
109 vsnprintf(&str[0], len + 1, format, args2); // This use of &str[0] guaranteed by C++11
110 }
111 va_end(args2);
112 va_end(args1);
113 return str;
114}
115
116// These implementation functions are inlined so that logging macros can be used via header-only
117// dependency on MochiCore. They do not require linking with MochiCore.
118namespace log_impl {
119
120#if MOCHI_ARCH_CPU
121inline auto& GetLogMutexRef() {
122 static std::recursive_mutex s_logMutex;
123 return s_logMutex;
124}
125inline auto& GetLogFnRef() {
126 static LogFn s_logFn;
127 return s_logFn;
128}
129inline auto& GetLogChannelsDisabledArrayRef() {
130 static std::array<bool, (size_t)LogChannel::Count> s_logChannelsDisabled = []() {
131 // All channels enabled by default
132 std::array<bool, (size_t)LogChannel::Count> disabledChannels = {};
133 // Except for these, which are disabled:
134 disabledChannels[(size_t)LogChannel::Verbose] = true;
135 return disabledChannels;
136 }();
137 return s_logChannelsDisabled;
138}
139#endif // MOCHI_ARCH_CPU
140
141inline void DefaultLogFn(LogChannel channel, std::string msg, char const* file, int line) {
142 char const* channelTag = (channel == LogChannel::Warning) ? " [WARNING]"
143 : (channel == LogChannel::Error) ? " [ERROR]"
144 : "";
145 auto fmtMsg = Format("%s(%d): [Mochi]%s %s", file, line, channelTag, msg.c_str());
146 printf("%s", fmtMsg.c_str());
147
148#if MOCHI_PLATFORM_WINDOWS && !defined(__UNREAL__)
149 // Logging to stdout is not automatically displayed in the Visual Studio debugger,
150 // so we have to do that explicitly.
151 ::OutputDebugStringA(fmtMsg.c_str());
152#endif // MOCHI_PLATFORM_WINDOWS
153}
154
155} // namespace log_impl
156
157inline void FlushLog() {
158 // TODO: Allow users who register a custom logging callback to also implement FlushLog.
159#if MOCHI_ARCH_CPU
160 fflush(stdout);
161 fflush(stderr);
162#endif
163}
164
166#if MOCHI_ARCH_CPU
167 std::lock_guard<std::recursive_mutex> lock(log_impl::GetLogMutexRef());
168 auto const& logFn = log_impl::GetLogFnRef();
169 return logFn ? logFn : LogFn{&log_impl::DefaultLogFn};
170#else
171 return LogFn{&log_impl::DefaultLogFn};
172#endif
173}
174
175inline void SetLogCallback([[maybe_unused]] LogFn fn) {
176#if MOCHI_ARCH_CPU
177 std::lock_guard<std::recursive_mutex> lock(log_impl::GetLogMutexRef());
178 auto& logFn = log_impl::GetLogFnRef();
179 logFn = fn ? fn : LogFn{&log_impl::DefaultLogFn};
180#endif
181}
182
183inline void EnableLogChannel(LogChannel channel, [[maybe_unused]] bool enable) {
184 if ((size_t)channel >= (size_t)LogChannel::Count)
186 MOCHI_LOG_WARNING("Requested LogChannel (%d) is invalid and will be ignored.", (int)channel);
187 return;
188 }
189#if MOCHI_ARCH_CPU
190 std::lock_guard<std::recursive_mutex> lock(log_impl::GetLogMutexRef());
191 log_impl::GetLogChannelsDisabledArrayRef()[(size_t)channel] = !enable;
192#endif
193}
194
195inline bool IsLogChannelEnabled(LogChannel channel) {
196 if ((size_t)channel >= (size_t)LogChannel::Count)
198 return false;
199 }
200#if MOCHI_ARCH_CPU
201 std::lock_guard<std::recursive_mutex> lock(log_impl::GetLogMutexRef());
202 auto const& isChannelDisabled = log_impl::GetLogChannelsDisabledArrayRef();
203 return !isChannelDisabled[(size_t)channel];
204#else
205 return true;
206#endif
207}
208
209inline void Log(LogChannel channel, std::string msg, char const* file, int line, bool newline) {
210 if (newline) {
211 msg += "\n";
212 }
213 GetLogCallback()(channel, msg.c_str(), file, line);
214}
215
216} // namespace superdex
#define MOCHI_LOG_WARNING(...)
Definition log.h:43
#define MOCHI_UNLIKELY
#define MOCHI_LIKELY
std::function< void(LogChannel, char const *message, char const *file, int line)> LogFn
Definition log.h:65
LogChannel
Definition log.h:37
void Log(LogChannel channel, std::string msg, char const *file, int line, bool newline)
Definition log.h:209
void EnableLogChannel(LogChannel channel, bool enable)
Definition log.h:183
void SetLogCallback(LogFn fn)
Definition log.h:175
bool IsLogChannelEnabled(LogChannel channel)
Definition log.h:195
void FlushLog()
Definition log.h:157
LogFn GetLogCallback()
Definition log.h:165
std::string Format()
Definition log.h:96
@ Count
Number of actor type enum values.
Definition mochi_enums.h:38