Bug 1816170 - Disable perftest-on-autoland cron. r=aglavic
[gecko.git] / xpcom / base / Logging.h
blob6ed2752315a04300fc5aeae1aa856b1e0b5d9220
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 * @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; }
157 private:
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;
166 char* mName;
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.
176 * Example usage:
177 * static LazyLogModule sLayoutLog("layout");
179 * void Foo() {
180 * MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
183 class LazyLogModule final {
184 public:
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);
196 mLog = tmp;
199 return tmp;
202 private:
203 const char* const mLogName;
205 Atomic<LogModule*, ReleaseAcquire> mLog;
208 namespace detail {
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))
232 #else
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...
238 // }
239 # define MOZ_LOG_TEST(_module, _level) false
240 #endif
242 // The natural definition of the MOZ_LOG macro would expand to:
244 // do {
245 // if (MOZ_LOG_TEST(_module, _level)) {
246 // mozilla::detail::log_print(_module, ...);
247 // }
248 // } while (0)
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:
261 // do {
262 // ::mozilla::LogModule* real_module = _module;
263 // if (MOZ_LOG_TEST(real_module, _level)) {
264 // mozilla::detail::log_print(real_module, ...);
265 // }
266 // } while (0)
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) \
286 do { \
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); \
292 } while (0)
293 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
294 do { \
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); \
300 } while (0)
301 #else
302 # define MOZ_LOG(_module, _level, _args) \
303 do { \
304 if (MOZ_LOG_TEST(_module, _level)) { \
305 mozilla::detail::log_print(_module, _level, \
306 MOZ_LOG_EXPAND_ARGS _args); \
308 } while (0)
309 # define MOZ_LOG_DURATION(_module, _level, start, _args) \
310 do { \
311 if (MOZ_LOG_TEST(_module, _level)) { \
312 mozilla::detail::log_print(_module, _level, start, \
313 MOZ_LOG_EXPAND_ARGS _args); \
315 } while (0)
316 #endif
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