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"
20 // We normally have logging enabled everywhere, but measurements showed that
21 // having logging enabled on Android is quite expensive (hundreds of kilobytes
22 // for both the format strings for logging and the code to perform all the
23 // logging calls). Because retrieving logs from a mobile device is
24 // comparatively more difficult for Android than it is for desktop and because
25 // desktop machines tend to be less space/bandwidth-constrained than Android
26 // devices, we've chosen to leave logging enabled on desktop, but disabled on
27 // Android. Given that logging can still be useful for development purposes,
28 // however, we leave logging enabled on Android developer builds.
29 #if !defined(ANDROID) || !defined(RELEASE_OR_BETA)
30 # define MOZ_LOGGING_ENABLED 1
32 # define MOZ_LOGGING_ENABLED 0
35 // The mandatory extension we add to log files. Note that rotate will append
36 // the file piece number still at the end.
37 #define MOZ_LOG_FILE_EXTENSION ".moz_log"
39 // Token for Process ID substitution.
40 #define MOZ_LOG_PID_TOKEN "%PID"
46 // While not a 100% mapping to PR_LOG's numeric values, mozilla::LogLevel does
47 // maintain a direct mapping for the Disabled, Debug and Verbose levels.
49 // Mappings of LogLevel to PR_LOG's numeric values:
51 // +---------+------------------+-----------------+
52 // | Numeric | NSPR Logging | Mozilla Logging |
53 // +---------+------------------+-----------------+
54 // | 0 | PR_LOG_NONE | Disabled |
55 // | 1 | PR_LOG_ALWAYS | Error |
56 // | 2 | PR_LOG_ERROR | Warning |
57 // | 3 | PR_LOG_WARNING | Info |
58 // | 4 | PR_LOG_DEBUG | Debug |
59 // | 5 | PR_LOG_DEBUG + 1 | Verbose |
60 // +---------+------------------+-----------------+
72 * Safely converts an integer into a valid LogLevel.
74 LogLevel
ToLogLevel(int32_t aLevel
);
78 ~LogModule() { ::free(mName
); }
81 * Retrieves the module with the given name. If it does not already exist
84 * @param aName The name of the module.
85 * @return A log module for the given name. This may be shared.
87 static LogModule
* Get(const char* aName
);
90 * Logging processes -MOZ_LOG and -MOZ_LOG_FILE command line arguments
91 * to override or set modules and the file as if passed through MOZ_LOG
92 * and MOZ_LOG_FILE env vars. It's fine to pass (0, nullptr) if args
93 * are not accessible in the caller's context, it will just do nothing.
94 * Note that the args take effect (are processed) only when this function
95 * is called the first time.
97 static void Init(int argc
, char* argv
[]);
100 * Sets the log file to the given filename.
102 static void SetLogFile(const char* aFilename
);
105 * @param aBuffer - pointer to a buffer
106 * @param aLength - the length of the buffer
108 * @return the actual length of the filepath.
110 static uint32_t GetLogFile(char* aBuffer
, size_t aLength
);
113 * @param aAddTimestamp If we should log a time stamp with every message.
115 static void SetAddTimestamp(bool aAddTimestamp
);
118 * @param aIsSync If we should flush the file after every logged message.
120 static void SetIsSync(bool aIsSync
);
123 * @param aCaptureStacks If we should capture stacks for the Firefox
124 * Profiler markers that are recorded for for each log entry.
126 static void SetCaptureStacks(bool aCaptureStacks
);
129 * Indicates whether or not the given log level is enabled.
131 bool ShouldLog(LogLevel aLevel
) const { return mLevel
>= aLevel
; }
134 * Retrieves the log module's current level.
136 LogLevel
Level() const { return mLevel
; }
139 * Sets the log module's level.
141 void SetLevel(LogLevel level
);
144 * Print a log message for this module.
146 void Printv(LogLevel aLevel
, const char* aFmt
, va_list aArgs
) const
147 MOZ_FORMAT_PRINTF(3, 0);
149 void Printv(LogLevel aLevel
, const TimeStamp
* aStart
, const char* aFmt
,
150 va_list aArgs
) const MOZ_FORMAT_PRINTF(4, 0);
153 * Retrieves the module name.
155 const char* Name() const { return mName
; }
158 friend class LogModuleManager
;
160 explicit LogModule(const char* aName
, LogLevel aLevel
)
161 : mName(strdup(aName
)), mLevel(aLevel
) {}
163 LogModule(LogModule
&) = delete;
164 LogModule
& operator=(const LogModule
&) = delete;
168 Atomic
<LogLevel
, Relaxed
> mLevel
;
172 * Helper class that lazy loads the given log module. This is safe to use for
173 * declaring static references to log modules and can be used as a replacement
174 * for accessing a LogModule directly.
177 * static LazyLogModule sLayoutLog("layout");
180 * MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
183 class LazyLogModule final
{
185 explicit constexpr LazyLogModule(const char* aLogName
)
186 : mLogName(aLogName
), mLog(nullptr) {}
188 MOZ_NEVER_INLINE_DEBUG
operator LogModule
*() {
189 // NB: The use of an atomic makes the reading and assignment of mLog
190 // thread-safe. There is a small chance that mLog will be set more
191 // than once, but that's okay as it will be set to the same LogModule
192 // instance each time. Also note LogModule::Get is thread-safe.
193 LogModule
* tmp
= mLog
;
194 if (MOZ_UNLIKELY(!tmp
)) {
195 tmp
= LogModule::Get(mLogName
);
203 const char* const mLogName
;
205 Atomic
<LogModule
*, ReleaseAcquire
> mLog
;
210 inline bool log_test(const LogModule
* module
, LogLevel level
) {
211 MOZ_ASSERT(level
!= LogLevel::Disabled
);
212 return module
&& module
->ShouldLog(level
);
215 void log_print(const LogModule
* aModule
, LogLevel aLevel
, const char* aFmt
, ...)
216 MOZ_FORMAT_PRINTF(3, 4);
218 void log_print(const LogModule
* aModule
, LogLevel aLevel
, TimeStamp
* aStart
,
219 const char* aFmt
, ...) MOZ_FORMAT_PRINTF(4, 5);
220 } // namespace detail
222 } // namespace mozilla
224 // Helper macro used convert MOZ_LOG's third parameter, |_args|, from a
225 // parenthesized form to a varargs form. For example:
226 // ("%s", "a message") => "%s", "a message"
227 #define MOZ_LOG_EXPAND_ARGS(...) __VA_ARGS__
229 #if MOZ_LOGGING_ENABLED
230 # define MOZ_LOG_TEST(_module, _level) \
231 MOZ_UNLIKELY(mozilla::detail::log_test(_module, _level))
233 // Define away MOZ_LOG_TEST here so the compiler will fold away entire
234 // logging blocks via dead code elimination, e.g.:
236 // if (MOZ_LOG_TEST(...)) {
237 // ...compute things to log and log them...
239 # define MOZ_LOG_TEST(_module, _level) false
242 // The natural definition of the MOZ_LOG macro would expand to:
245 // if (MOZ_LOG_TEST(_module, _level)) {
246 // mozilla::detail::log_print(_module, ...);
250 // However, since _module is a LazyLogModule, and we need to call
251 // LazyLogModule::operator() to get a LogModule* for the MOZ_LOG_TEST
252 // macro and for the logging call, we'll wind up doing *two* calls, one
253 // for each, rather than a single call. The compiler is not able to
254 // fold the two calls into one, and the extra call can have a
255 // significant effect on code size. (Making LazyLogModule::operator() a
256 // `const` function does not have any effect.)
258 // Therefore, we will have to make a single call ourselves. But again,
259 // the natural definition:
262 // ::mozilla::LogModule* real_module = _module;
263 // if (MOZ_LOG_TEST(real_module, _level)) {
264 // mozilla::detail::log_print(real_module, ...);
268 // also has a problem: if logging is disabled, then we will call
269 // LazyLogModule::operator() unnecessarily, and the compiler will not be
270 // able to optimize away the call as dead code. We would like to avoid
271 // such a scenario, as the whole point of disabling logging is for the
272 // logging statements to not generate any code.
274 // Therefore, we need different definitions of MOZ_LOG, depending on
275 // whether logging is enabled or not. (We need an actual definition of
276 // MOZ_LOG even when logging is disabled to ensure the compiler sees that
277 // variables only used during logging code are actually used, even if the
278 // code will never be executed.) Hence, the following code.
280 // MOZ_LOG_DURATION takes a start time, and will generate a time range
281 // in the logs. Also, if the Firefox Profiler is running,
282 // MOZ_LOG_DURATION will generate a marker with a time duration
283 // instead of a single point in time.
284 #if MOZ_LOGGING_ENABLED
285 # define MOZ_LOG(_module, _level, _args) \
287 const ::mozilla::LogModule* moz_real_module = _module; \
288 if (MOZ_LOG_TEST(moz_real_module, _level)) { \
289 mozilla::detail::log_print(moz_real_module, _level, \
290 MOZ_LOG_EXPAND_ARGS _args); \
293 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
295 const ::mozilla::LogModule* moz_real_module = _module; \
296 if (MOZ_LOG_TEST(moz_real_module, _level)) { \
297 mozilla::detail::log_print(moz_real_module, _level, start, \
298 MOZ_LOG_EXPAND_ARGS _args); \
302 # define MOZ_LOG(_module, _level, _args) \
304 if (MOZ_LOG_TEST(_module, _level)) { \
305 mozilla::detail::log_print(_module, _level, \
306 MOZ_LOG_EXPAND_ARGS _args); \
309 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
311 if (MOZ_LOG_TEST(_module, _level)) { \
312 mozilla::detail::log_print(_module, _level, start, \
313 MOZ_LOG_EXPAND_ARGS _args); \
318 // This #define is a Logging.h-only knob! Don't encourage people to get fancy
319 // with their log definitions by exporting it outside of Logging.h.
320 #undef MOZ_LOGGING_ENABLED
322 #endif // mozilla_logging_h