Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / xpcom / base / Logging.h
blobc417bdbf770b13ef9971c7fb4c45a47e60c7b8a0
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"
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
31 #else
32 # define MOZ_LOGGING_ENABLED 0
33 #endif
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"
42 namespace mozilla {
44 class TimeStamp;
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 // +---------+------------------+-----------------+
62 enum class LogLevel {
63 Disabled = 0,
64 Error,
65 Warning,
66 Info,
67 Debug,
68 Verbose,
71 /**
72 * Safely converts an integer into a valid LogLevel.
74 LogLevel ToLogLevel(int32_t aLevel);
76 class LogModule {
77 public:
78 ~LogModule() { ::free(mName); }
80 /**
81 * Retrieves the module with the given name. If it does not already exist
82 * it will be created.
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);
89 /**
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[]);
99 /**
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 * Indicates whether or not the given log level is enabled.
125 bool ShouldLog(LogLevel aLevel) const { return mLevel >= aLevel; }
128 * Retrieves the log module's current level.
130 LogLevel Level() const { return mLevel; }
133 * Sets the log module's level.
135 void SetLevel(LogLevel level);
138 * Print a log message for this module.
140 void Printv(LogLevel aLevel, const char* aFmt, va_list aArgs) const
141 MOZ_FORMAT_PRINTF(3, 0);
143 void Printv(LogLevel aLevel, const TimeStamp* aStart, const char* aFmt,
144 va_list aArgs) const MOZ_FORMAT_PRINTF(4, 0);
147 * Retrieves the module name.
149 const char* Name() const { return mName; }
151 private:
152 friend class LogModuleManager;
154 explicit LogModule(const char* aName, LogLevel aLevel)
155 : mName(strdup(aName)), mLevel(aLevel) {}
157 LogModule(LogModule&) = delete;
158 LogModule& operator=(const LogModule&) = delete;
160 char* mName;
162 Atomic<LogLevel, Relaxed> mLevel;
166 * Helper class that lazy loads the given log module. This is safe to use for
167 * declaring static references to log modules and can be used as a replacement
168 * for accessing a LogModule directly.
170 * Example usage:
171 * static LazyLogModule sLayoutLog("layout");
173 * void Foo() {
174 * MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
177 class LazyLogModule final {
178 public:
179 explicit constexpr LazyLogModule(const char* aLogName)
180 : mLogName(aLogName), mLog(nullptr) {}
182 MOZ_NEVER_INLINE_DEBUG operator LogModule*() {
183 // NB: The use of an atomic makes the reading and assignment of mLog
184 // thread-safe. There is a small chance that mLog will be set more
185 // than once, but that's okay as it will be set to the same LogModule
186 // instance each time. Also note LogModule::Get is thread-safe.
187 LogModule* tmp = mLog;
188 if (MOZ_UNLIKELY(!tmp)) {
189 tmp = LogModule::Get(mLogName);
190 mLog = tmp;
193 return tmp;
196 private:
197 const char* const mLogName;
199 Atomic<LogModule*, ReleaseAcquire> mLog;
202 namespace detail {
204 inline bool log_test(const LogModule* module, LogLevel level) {
205 MOZ_ASSERT(level != LogLevel::Disabled);
206 return module && module->ShouldLog(level);
209 void log_print(const LogModule* aModule, LogLevel aLevel, const char* aFmt, ...)
210 MOZ_FORMAT_PRINTF(3, 4);
212 void log_print(const LogModule* aModule, LogLevel aLevel, TimeStamp* aStart,
213 const char* aFmt, ...) MOZ_FORMAT_PRINTF(4, 5);
214 } // namespace detail
216 } // namespace mozilla
218 // Helper macro used convert MOZ_LOG's third parameter, |_args|, from a
219 // parenthesized form to a varargs form. For example:
220 // ("%s", "a message") => "%s", "a message"
221 #define MOZ_LOG_EXPAND_ARGS(...) __VA_ARGS__
223 #if MOZ_LOGGING_ENABLED
224 # define MOZ_LOG_TEST(_module, _level) \
225 MOZ_UNLIKELY(mozilla::detail::log_test(_module, _level))
226 #else
227 // Define away MOZ_LOG_TEST here so the compiler will fold away entire
228 // logging blocks via dead code elimination, e.g.:
230 // if (MOZ_LOG_TEST(...)) {
231 // ...compute things to log and log them...
232 // }
233 # define MOZ_LOG_TEST(_module, _level) false
234 #endif
236 // The natural definition of the MOZ_LOG macro would expand to:
238 // do {
239 // if (MOZ_LOG_TEST(_module, _level)) {
240 // mozilla::detail::log_print(_module, ...);
241 // }
242 // } while (0)
244 // However, since _module is a LazyLogModule, and we need to call
245 // LazyLogModule::operator() to get a LogModule* for the MOZ_LOG_TEST
246 // macro and for the logging call, we'll wind up doing *two* calls, one
247 // for each, rather than a single call. The compiler is not able to
248 // fold the two calls into one, and the extra call can have a
249 // significant effect on code size. (Making LazyLogModule::operator() a
250 // `const` function does not have any effect.)
252 // Therefore, we will have to make a single call ourselves. But again,
253 // the natural definition:
255 // do {
256 // ::mozilla::LogModule* real_module = _module;
257 // if (MOZ_LOG_TEST(real_module, _level)) {
258 // mozilla::detail::log_print(real_module, ...);
259 // }
260 // } while (0)
262 // also has a problem: if logging is disabled, then we will call
263 // LazyLogModule::operator() unnecessarily, and the compiler will not be
264 // able to optimize away the call as dead code. We would like to avoid
265 // such a scenario, as the whole point of disabling logging is for the
266 // logging statements to not generate any code.
268 // Therefore, we need different definitions of MOZ_LOG, depending on
269 // whether logging is enabled or not. (We need an actual definition of
270 // MOZ_LOG even when logging is disabled to ensure the compiler sees that
271 // variables only used during logging code are actually used, even if the
272 // code will never be executed.) Hence, the following code.
274 // MOZ_LOG_DURATION takes a start time, and will generate a time range
275 // in the logs. Also, if 'profilermarkers' is used in the env var
276 // MOZ_LOG, MOZ_LOG_DURATION will generate a marker with a time
277 // duration instead of a single point in time.
278 #if MOZ_LOGGING_ENABLED
279 # define MOZ_LOG(_module, _level, _args) \
280 do { \
281 const ::mozilla::LogModule* moz_real_module = _module; \
282 if (MOZ_LOG_TEST(moz_real_module, _level)) { \
283 mozilla::detail::log_print(moz_real_module, _level, \
284 MOZ_LOG_EXPAND_ARGS _args); \
286 } while (0)
287 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
288 do { \
289 const ::mozilla::LogModule* moz_real_module = _module; \
290 if (MOZ_LOG_TEST(moz_real_module, _level)) { \
291 mozilla::detail::log_print(moz_real_module, _level, start, \
292 MOZ_LOG_EXPAND_ARGS _args); \
294 } while (0)
295 #else
296 # define MOZ_LOG(_module, _level, _args) \
297 do { \
298 if (MOZ_LOG_TEST(_module, _level)) { \
299 mozilla::detail::log_print(_module, _level, \
300 MOZ_LOG_EXPAND_ARGS _args); \
302 } while (0)
303 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
304 do { \
305 if (MOZ_LOG_TEST(_module, _level)) { \
306 mozilla::detail::log_print(_module, _level, start, \
307 MOZ_LOG_EXPAND_ARGS _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