Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/Logging.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#ifndef mozilla_logging_h
8
#define mozilla_logging_h
9
10
#include <string.h>
11
#include <stdarg.h>
12
13
#include "mozilla/Assertions.h"
14
#include "mozilla/Atomics.h"
15
#include "mozilla/Attributes.h"
16
#include "mozilla/Likely.h"
17
#include "mozilla/Poison.h"
18
19
// We normally have logging enabled everywhere, but measurements showed that
20
// having logging enabled on Android is quite expensive (hundreds of kilobytes
21
// for both the format strings for logging and the code to perform all the
22
// logging calls).  Because retrieving logs from a mobile device is
23
// comparatively more difficult for Android than it is for desktop and because
24
// desktop machines tend to be less space/bandwidth-constrained than Android
25
// devices, we've chosen to leave logging enabled on desktop, but disabled on
26
// Android.  Given that logging can still be useful for development purposes,
27
// however, we leave logging enabled on Android developer builds.
28
#if !defined(ANDROID) || !defined(RELEASE_OR_BETA)
29
#define MOZ_LOGGING_ENABLED 1
30
#else
31
#define MOZ_LOGGING_ENABLED 0
32
#endif
33
34
namespace mozilla {
35
36
// While not a 100% mapping to PR_LOG's numeric values, mozilla::LogLevel does
37
// maintain a direct mapping for the Disabled, Debug and Verbose levels.
38
//
39
// Mappings of LogLevel to PR_LOG's numeric values:
40
//
41
//   +---------+------------------+-----------------+
42
//   | Numeric | NSPR Logging     | Mozilla Logging |
43
//   +---------+------------------+-----------------+
44
//   |       0 | PR_LOG_NONE      | Disabled        |
45
//   |       1 | PR_LOG_ALWAYS    | Error           |
46
//   |       2 | PR_LOG_ERROR     | Warning         |
47
//   |       3 | PR_LOG_WARNING   | Info            |
48
//   |       4 | PR_LOG_DEBUG     | Debug           |
49
//   |       5 | PR_LOG_DEBUG + 1 | Verbose         |
50
//   +---------+------------------+-----------------+
51
//
52
enum class LogLevel {
53
  Disabled = 0,
54
  Error,
55
  Warning,
56
  Info,
57
  Debug,
58
  Verbose,
59
};
60
61
/**
62
 * Safely converts an integer into a valid LogLevel.
63
 */
64
LogLevel ToLogLevel(int32_t aLevel);
65
66
class LogModule
67
{
68
public:
69
0
  ~LogModule() { ::free(mName); }
70
71
  /**
72
   * Retrieves the module with the given name. If it does not already exist
73
   * it will be created.
74
   *
75
   * @param aName The name of the module.
76
   * @return A log module for the given name. This may be shared.
77
   */
78
  static LogModule* Get(const char* aName);
79
80
  /**
81
   * Logging processes -MOZ_LOG and -MOZ_LOG_FILE command line arguments
82
   * to override or set modules and the file as if passed through MOZ_LOG
83
   * and MOZ_LOG_FILE env vars.  It's fine to pass (0, nullptr) if args
84
   * are not accessible in the caller's context, it will just do nothing.
85
   * Note that the args take effect (are processed) only when this function
86
   * is called the first time.
87
   */
88
  static void Init(int argc, char* argv[]);
89
90
  /**
91
   * Sets the log file to the given filename.
92
   */
93
  static void SetLogFile(const char* aFilename);
94
95
  /**
96
   * @param aBuffer - pointer to a buffer
97
   * @param aLength - the length of the buffer
98
   *
99
   * @return the actual length of the filepath.
100
   */
101
  static uint32_t GetLogFile(char *aBuffer, size_t aLength);
102
103
  /**
104
   * @param aAddTimestamp If we should log a time stamp with every message.
105
   */
106
  static void SetAddTimestamp(bool aAddTimestamp);
107
108
  /**
109
   * @param aIsSync If we should flush the file after every logged message.
110
   */
111
  static void SetIsSync(bool aIsSync);
112
113
  /**
114
   * Indicates whether or not the given log level is enabled.
115
   */
116
  bool ShouldLog(LogLevel aLevel) const { return mLevel >= aLevel; }
117
118
  /**
119
   * Retrieves the log module's current level.
120
   */
121
0
  LogLevel Level() const { return mLevel; }
122
123
  /**
124
   * Sets the log module's level.
125
   */
126
0
  void SetLevel(LogLevel level) { mLevel = level; }
127
128
  /**
129
   * Print a log message for this module.
130
   */
131
  void Printv(LogLevel aLevel, const char* aFmt, va_list aArgs) const MOZ_FORMAT_PRINTF(3, 0);
132
133
  /**
134
   * Retrieves the module name.
135
   */
136
0
  const char* Name() const { return mName; }
137
138
private:
139
  friend class LogModuleManager;
140
141
  explicit LogModule(const char* aName, LogLevel aLevel)
142
    : mName(strdup(aName)), mLevel(aLevel)
143
0
  {
144
0
  }
145
146
  LogModule(LogModule&) = delete;
147
  LogModule& operator=(const LogModule&) = delete;
148
149
  char* mName;
150
151
  // Logging atomics and other state are not preserved by web replay, as they
152
  // may be accessed during the GC and other areas where recorded events are
153
  // not allowed.
154
  Atomic<LogLevel, Relaxed, recordreplay::Behavior::DontPreserve> mLevel;
155
};
156
157
/**
158
 * Helper class that lazy loads the given log module. This is safe to use for
159
 * declaring static references to log modules and can be used as a replacement
160
 * for accessing a LogModule directly.
161
 *
162
 * Example usage:
163
 *   static LazyLogModule sLayoutLog("layout");
164
 *
165
 *   void Foo() {
166
 *     MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
167
 *   }
168
 */
169
class LazyLogModule final
170
{
171
public:
172
  explicit constexpr LazyLogModule(const char* aLogName)
173
    : mLogName(aLogName)
174
    , mLog(nullptr)
175
0
  {
176
0
  }
177
178
  operator LogModule*();
179
180
private:
181
  const char* const mLogName;
182
  const CorruptionCanaryForStatics mCanary;
183
184
  // As for LogModule::mLevel, don't preserve behavior for this atomic when
185
  // recording/replaying.
186
  Atomic<LogModule*, ReleaseAcquire, recordreplay::Behavior::DontPreserve> mLog;
187
};
188
189
namespace detail {
190
191
23.5M
inline bool log_test(const LogModule* module, LogLevel level) {
192
23.5M
  MOZ_ASSERT(level != LogLevel::Disabled);
193
23.5M
  return module && module->ShouldLog(level);
194
23.5M
}
195
196
void log_print(const LogModule* aModule,
197
               LogLevel aLevel,
198
               const char* aFmt, ...) MOZ_FORMAT_PRINTF(3, 4);
199
} // namespace detail
200
201
} // namespace mozilla
202
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
0
#define MOZ_LOG_EXPAND_ARGS(...) __VA_ARGS__
207
208
#if MOZ_LOGGING_ENABLED
209
23.5M
#define MOZ_LOG_TEST(_module,_level) mozilla::detail::log_test(_module, _level)
210
#else
211
// Define away MOZ_LOG_TEST here so the compiler will fold away entire
212
// logging blocks via dead code elimination, e.g.:
213
//
214
//   if (MOZ_LOG_TEST(...)) {
215
//     ...compute things to log and log them...
216
//   }
217
#define MOZ_LOG_TEST(_module,_level) false
218
#endif
219
220
// The natural definition of the MOZ_LOG macro would expand to:
221
//
222
//   do {
223
//     if (MOZ_LOG_TEST(_module, _level)) {
224
//       mozilla::detail::log_print(_module, ...);
225
//     }
226
//   } while (0)
227
//
228
// However, since _module is a LazyLogModule, and we need to call
229
// LazyLogModule::operator() to get a LogModule* for the MOZ_LOG_TEST
230
// macro and for the logging call, we'll wind up doing *two* calls, one
231
// for each, rather than a single call.  The compiler is not able to
232
// fold the two calls into one, and the extra call can have a
233
// significant effect on code size.  (Making LazyLogModule::operator() a
234
// `const` function does not have any effect.)
235
//
236
// Therefore, we will have to make a single call ourselves.  But again,
237
// the natural definition:
238
//
239
//   do {
240
//     ::mozilla::LogModule* real_module = _module;
241
//     if (MOZ_LOG_TEST(real_module, _level)) {
242
//       mozilla::detail::log_print(real_module, ...);
243
//     }
244
//   } while (0)
245
//
246
// also has a problem: if logging is disabled, then we will call
247
// LazyLogModule::operator() unnecessarily, and the compiler will not be
248
// able to optimize away the call as dead code.  We would like to avoid
249
// such a scenario, as the whole point of disabling logging is for the
250
// logging statements to not generate any code.
251
//
252
// Therefore, we need different definitions of MOZ_LOG, depending on
253
// whether logging is enabled or not.  (We need an actual definition of
254
// MOZ_LOG even when logging is disabled to ensure the compiler sees that
255
// variables only used during logging code are actually used, even if the
256
// code will never be executed.)  Hence, the following code.
257
#if MOZ_LOGGING_ENABLED
258
#define MOZ_LOG(_module,_level,_args)                                         \
259
20.2M
  do {                                                                        \
260
20.2M
    const ::mozilla::LogModule* moz_real_module = _module;                    \
261
20.2M
    if (MOZ_LOG_TEST(moz_real_module,_level)) {                               \
262
0
      mozilla::detail::log_print(moz_real_module, _level, MOZ_LOG_EXPAND_ARGS _args); \
263
0
    }                                                                         \
264
20.2M
  } while (0)
265
#else
266
#define MOZ_LOG(_module,_level,_args)                                         \
267
  do {                                                                        \
268
    if (MOZ_LOG_TEST(_module,_level)) {                        \
269
      mozilla::detail::log_print(_module, _level, MOZ_LOG_EXPAND_ARGS _args); \
270
    }                                                                         \
271
  } while (0)
272
#endif
273
274
// This #define is a Logging.h-only knob!  Don't encourage people to get fancy
275
// with their log definitions by exporting it outside of Logging.h.
276
#undef MOZ_LOGGING_ENABLED
277
278
#endif // mozilla_logging_h