Bug 1910362 - Create new Nimbus helper r=aaronmt,ohorvath
[gecko.git] / xpcom / base / Logging.h
blob13de0c015d7d03066049af1701b186a900fe4e3e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_logging_h
8 #define mozilla_logging_h
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdarg.h>
15 #include "mozilla/Assertions.h"
16 #include "mozilla/Atomics.h"
17 #include "mozilla/Attributes.h"
18 #include "mozilla/Likely.h"
19 #include "mozilla/LoggingCore.h"
21 #include "fmt/format.h"
23 #define MOZ_LOGGING_ENABLED 1
25 // The mandatory extension we add to log files. Note that rotate will append
26 // the file piece number still at the end.
27 #define MOZ_LOG_FILE_EXTENSION ".moz_log"
29 // Token for Process ID substitution.
30 #define MOZ_LOG_PID_TOKEN "%PID"
32 namespace mozilla {
34 class TimeStamp;
36 class LogModule {
37 public:
38 ~LogModule() { ::free(mName); }
40 /**
41 * Retrieves the module with the given name. If it does not already exist
42 * it will be created.
44 * @param aName The name of the module.
45 * @return A log module for the given name. This may be shared.
47 static LogModule* Get(const char* aName);
49 /**
50 * Logging processes -MOZ_LOG and -MOZ_LOG_FILE command line arguments
51 * to override or set modules and the file as if passed through MOZ_LOG
52 * and MOZ_LOG_FILE env vars. It's fine to pass (0, nullptr) if args
53 * are not accessible in the caller's context, it will just do nothing.
54 * Note that the args take effect (are processed) only when this function
55 * is called the first time.
57 static void Init(int argc, char* argv[]);
59 /**
60 * Sets the log file to the given filename.
62 static void SetLogFile(const char* aFilename);
64 /**
65 * @param aBuffer - pointer to a buffer
66 * @param aLength - the length of the buffer
68 * @return the actual length of the filepath.
70 static uint32_t GetLogFile(char* aBuffer, size_t aLength);
72 /**
73 * @param aAddTimestamp If we should log a time stamp with every message.
75 static void SetAddTimestamp(bool aAddTimestamp);
77 /**
78 * @param aIsSync If we should flush the file after every logged message.
80 static void SetIsSync(bool aIsSync);
82 /**
83 * @param aCaptureStacks If we should capture stacks for the Firefox
84 * Profiler markers that are recorded for for each log entry.
86 static void SetCaptureStacks(bool aCaptureStacks);
88 /**
89 * Disable all log modules.
91 static void DisableModules();
93 /**
94 * Indicates whether or not the given log level is enabled.
96 bool ShouldLog(LogLevel aLevel) const { return mLevel >= aLevel; }
98 /**
99 * Retrieves the log module's current level.
101 LogLevel Level() const { return mLevel; }
104 * Sets the log module's level.
106 void SetLevel(LogLevel level);
109 * Print a log message for this module.
111 void Printv(LogLevel aLevel, const char* aFmt, va_list aArgs) const
112 MOZ_FORMAT_PRINTF(3, 0);
114 void Printv(LogLevel aLevel, const TimeStamp* aStart, const char* aFmt,
115 va_list aArgs) const MOZ_FORMAT_PRINTF(4, 0);
118 * Use {fmt} for specifying format
120 void PrintvFmt(LogLevel aLevel, fmt::string_view aFmt,
121 fmt::format_args aArgs) const;
124 * Retrieves the module name.
126 const char* Name() const { return mName; }
128 AtomicLogLevel& LevelRef() { return mLevel; }
130 private:
131 friend class LogModuleManager;
133 explicit LogModule(const char* aName, LogLevel aLevel)
134 : mName(strdup(aName)), mLevel(aLevel) {}
136 LogModule(LogModule&) = delete;
137 LogModule& operator=(const LogModule&) = delete;
139 char* mName;
141 AtomicLogLevel mLevel;
145 * Helper class that lazy loads the given log module. This is safe to use for
146 * declaring static references to log modules and can be used as a replacement
147 * for accessing a LogModule directly.
149 * Example usage:
150 * static LazyLogModule sLayoutLog("layout");
152 * void Foo() {
153 * MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
156 class LazyLogModule final {
157 public:
158 explicit constexpr LazyLogModule(const char* aLogName)
159 : mLogName(aLogName), mLog(nullptr) {}
161 MOZ_NEVER_INLINE_DEBUG operator LogModule*() {
162 // NB: The use of an atomic makes the reading and assignment of mLog
163 // thread-safe. There is a small chance that mLog will be set more
164 // than once, but that's okay as it will be set to the same LogModule
165 // instance each time. Also note LogModule::Get is thread-safe.
166 LogModule* tmp = mLog;
167 if (MOZ_UNLIKELY(!tmp)) {
168 tmp = LogModule::Get(mLogName);
169 mLog = tmp;
172 return tmp;
175 private:
176 const char* const mLogName;
178 Atomic<LogModule*, ReleaseAcquire> mLog;
181 namespace detail {
183 inline bool log_test(const LogModule* module, LogLevel level) {
184 MOZ_ASSERT(level != LogLevel::Disabled);
185 return module && module->ShouldLog(level);
188 void log_print(const LogModule* aModule, LogLevel aLevel, const char* aFmt, ...)
189 MOZ_FORMAT_PRINTF(3, 4);
191 template <typename... T>
192 inline void log_print_fmt(const LogModule* aModule, LogLevel aLevel,
193 fmt::format_string<T...> aFmt, T&&... aArgs) {
194 aModule->PrintvFmt(aLevel, aFmt, fmt::make_format_args(aArgs...));
197 void log_print(const LogModule* aModule, LogLevel aLevel, TimeStamp* aStart,
198 const char* aFmt, ...) MOZ_FORMAT_PRINTF(4, 5);
199 } // namespace detail
201 } // namespace mozilla
203 // Helper macro used convert MOZ_LOG's third parameter, |_args|, from a
204 // parenthesized form to a varargs form. For example:
205 // ("%s", "a message") => "%s", "a message"
206 #define MOZ_LOG_EXPAND_ARGS(...) __VA_ARGS__
208 #if MOZ_LOGGING_ENABLED
209 # define MOZ_LOG_TEST(_module, _level) \
210 MOZ_UNLIKELY(mozilla::detail::log_test(_module, _level))
211 #else
212 // Define away MOZ_LOG_TEST here so the compiler will fold away entire
213 // logging blocks via dead code elimination, e.g.:
215 // if (MOZ_LOG_TEST(...)) {
216 // ...compute things to log and log them...
217 // }
218 # define MOZ_LOG_TEST(_module, _level) false
219 #endif
221 // The natural definition of the MOZ_LOG macro would expand to:
223 // do {
224 // if (MOZ_LOG_TEST(_module, _level)) {
225 // mozilla::detail::log_print(_module, ...);
226 // }
227 // } while (0)
229 // However, since _module is a LazyLogModule, and we need to call
230 // LazyLogModule::operator() to get a LogModule* for the MOZ_LOG_TEST
231 // macro and for the logging call, we'll wind up doing *two* calls, one
232 // for each, rather than a single call. The compiler is not able to
233 // fold the two calls into one, and the extra call can have a
234 // significant effect on code size. (Making LazyLogModule::operator() a
235 // `const` function does not have any effect.)
237 // Therefore, we will have to make a single call ourselves. But again,
238 // the natural definition:
240 // do {
241 // ::mozilla::LogModule* real_module = _module;
242 // if (MOZ_LOG_TEST(real_module, _level)) {
243 // mozilla::detail::log_print(real_module, ...);
244 // }
245 // } while (0)
247 // also has a problem: if logging is disabled, then we will call
248 // LazyLogModule::operator() unnecessarily, and the compiler will not be
249 // able to optimize away the call as dead code. We would like to avoid
250 // such a scenario, as the whole point of disabling logging is for the
251 // logging statements to not generate any code.
253 // Therefore, we need different definitions of MOZ_LOG, depending on
254 // whether logging is enabled or not. (We need an actual definition of
255 // MOZ_LOG even when logging is disabled to ensure the compiler sees that
256 // variables only used during logging code are actually used, even if the
257 // code will never be executed.) Hence, the following code.
259 // MOZ_LOG_DURATION takes a start time, and will generate a time range
260 // in the logs. Also, if the Firefox Profiler is running,
261 // MOZ_LOG_DURATION will generate a marker with a time duration
262 // instead of a single point in time.
263 #if MOZ_LOGGING_ENABLED
264 # define MOZ_LOG(_module, _level, _args) \
265 do { \
266 const ::mozilla::LogModule* moz_real_module = _module; \
267 if (MOZ_LOG_TEST(moz_real_module, _level)) { \
268 mozilla::detail::log_print(moz_real_module, _level, \
269 MOZ_LOG_EXPAND_ARGS _args); \
271 } while (0)
272 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
273 do { \
274 const ::mozilla::LogModule* moz_real_module = _module; \
275 if (MOZ_LOG_TEST(moz_real_module, _level)) { \
276 mozilla::detail::log_print(moz_real_module, _level, start, \
277 MOZ_LOG_EXPAND_ARGS _args); \
279 } while (0)
280 # define MOZ_LOG_FMT(_module, _level, _fmt, ...) \
281 do { \
282 const ::mozilla::LogModule* moz_real_module = _module; \
283 if (MOZ_LOG_TEST(moz_real_module, _level)) { \
284 mozilla::detail::log_print_fmt(moz_real_module, _level, \
285 FMT_STRING(_fmt), ##__VA_ARGS__); \
287 } while (0)
288 #else
289 # define MOZ_LOG(_module, _level, _args) \
290 do { \
291 if (MOZ_LOG_TEST(_module, _level)) { \
292 mozilla::detail::log_print(_module, _level, \
293 MOZ_LOG_EXPAND_ARGS _args); \
295 } while (0)
296 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
297 do { \
298 if (MOZ_LOG_TEST(_module, _level)) { \
299 mozilla::detail::log_print(_module, _level, start, \
300 MOZ_LOG_EXPAND_ARGS _args); \
302 } while (0)
303 # define MOZ_LOG_FMT(_module, _level, _fmt, ...) \
304 do { \
305 if (MOZ_LOG_TEST(_module, _level)) { \
306 mozilla::detail::log_print_fmt(_module, _level, FMT_STRING(_fmt), \
307 ##__VA_ARGS__); \
309 } while (0)
310 #endif
312 // This #define is a Logging.h-only knob! Don't encourage people to get fancy
313 // with their log definitions by exporting it outside of Logging.h.
314 #undef MOZ_LOGGING_ENABLED
316 #endif // mozilla_logging_h