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
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"
38 ~LogModule() { ::free(mName
); }
41 * Retrieves the module with the given name. If it does not already exist
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
);
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
[]);
60 * Sets the log file to the given filename.
62 static void SetLogFile(const char* aFilename
);
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
);
73 * @param aAddTimestamp If we should log a time stamp with every message.
75 static void SetAddTimestamp(bool aAddTimestamp
);
78 * @param aIsSync If we should flush the file after every logged message.
80 static void SetIsSync(bool aIsSync
);
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
);
89 * Disable all log modules.
91 static void DisableModules();
94 * Indicates whether or not the given log level is enabled.
96 bool ShouldLog(LogLevel aLevel
) const { return mLevel
>= aLevel
; }
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
; }
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;
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.
150 * static LazyLogModule sLayoutLog("layout");
153 * MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
156 class LazyLogModule final
{
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
);
176 const char* const mLogName
;
178 Atomic
<LogModule
*, ReleaseAcquire
> mLog
;
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))
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...
218 # define MOZ_LOG_TEST(_module, _level) false
221 // The natural definition of the MOZ_LOG macro would expand to:
224 // if (MOZ_LOG_TEST(_module, _level)) {
225 // mozilla::detail::log_print(_module, ...);
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:
241 // ::mozilla::LogModule* real_module = _module;
242 // if (MOZ_LOG_TEST(real_module, _level)) {
243 // mozilla::detail::log_print(real_module, ...);
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) \
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); \
272 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
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); \
280 # define MOZ_LOG_FMT(_module, _level, _fmt, ...) \
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__); \
289 # define MOZ_LOG(_module, _level, _args) \
291 if (MOZ_LOG_TEST(_module, _level)) { \
292 mozilla::detail::log_print(_module, _level, \
293 MOZ_LOG_EXPAND_ARGS _args); \
296 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
298 if (MOZ_LOG_TEST(_module, _level)) { \
299 mozilla::detail::log_print(_module, _level, start, \
300 MOZ_LOG_EXPAND_ARGS _args); \
303 # define MOZ_LOG_FMT(_module, _level, _fmt, ...) \
305 if (MOZ_LOG_TEST(_module, _level)) { \
306 mozilla::detail::log_print_fmt(_module, _level, FMT_STRING(_fmt), \
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