Line data Source code
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 :
18 : // We normally have logging enabled everywhere, but measurements showed that
19 : // having logging enabled on Android is quite expensive (hundreds of kilobytes
20 : // for both the format strings for logging and the code to perform all the
21 : // logging calls). Because retrieving logs from a mobile device is
22 : // comparatively more difficult for Android than it is for desktop and because
23 : // desktop machines tend to be less space/bandwidth-constrained than Android
24 : // devices, we've chosen to leave logging enabled on desktop, but disabled on
25 : // Android. Given that logging can still be useful for development purposes,
26 : // however, we leave logging enabled on Android developer builds.
27 : #if !defined(ANDROID) || !defined(RELEASE_OR_BETA)
28 : #define MOZ_LOGGING_ENABLED 1
29 : #else
30 : #define MOZ_LOGGING_ENABLED 0
31 : #endif
32 :
33 : namespace mozilla {
34 :
35 : // While not a 100% mapping to PR_LOG's numeric values, mozilla::LogLevel does
36 : // maintain a direct mapping for the Disabled, Debug and Verbose levels.
37 : //
38 : // Mappings of LogLevel to PR_LOG's numeric values:
39 : //
40 : // +---------+------------------+-----------------+
41 : // | Numeric | NSPR Logging | Mozilla Logging |
42 : // +---------+------------------+-----------------+
43 : // | 0 | PR_LOG_NONE | Disabled |
44 : // | 1 | PR_LOG_ALWAYS | Error |
45 : // | 2 | PR_LOG_ERROR | Warning |
46 : // | 3 | PR_LOG_WARNING | Info |
47 : // | 4 | PR_LOG_DEBUG | Debug |
48 : // | 5 | PR_LOG_DEBUG + 1 | Verbose |
49 : // +---------+------------------+-----------------+
50 : //
51 : enum class LogLevel {
52 : Disabled = 0,
53 : Error,
54 : Warning,
55 : Info,
56 : Debug,
57 : Verbose,
58 : };
59 :
60 : /**
61 : * Safely converts an integer into a valid LogLevel.
62 : */
63 : LogLevel ToLogLevel(int32_t aLevel);
64 :
65 : class LogModule
66 : {
67 : public:
68 0 : ~LogModule() { ::free(mName); }
69 :
70 : /**
71 : * Retrieves the module with the given name. If it does not already exist
72 : * it will be created.
73 : *
74 : * @param aName The name of the module.
75 : * @return A log module for the given name. This may be shared.
76 : */
77 : static LogModule* Get(const char* aName);
78 :
79 : static void Init();
80 :
81 : /**
82 : * Sets the log file to the given filename.
83 : */
84 : static void SetLogFile(const char* aFilename);
85 :
86 : /**
87 : * @param aBuffer - pointer to a buffer
88 : * @param aLength - the length of the buffer
89 : *
90 : * @return the actual length of the filepath.
91 : */
92 : static uint32_t GetLogFile(char *aBuffer, size_t aLength);
93 :
94 : /**
95 : * @param aAddTimestamp If we should log a time stamp with every message.
96 : */
97 : static void SetAddTimestamp(bool aAddTimestamp);
98 :
99 : /**
100 : * @param aIsSync If we should flush the file after every logged message.
101 : */
102 : static void SetIsSync(bool aIsSync);
103 :
104 : /**
105 : * Indicates whether or not the given log level is enabled.
106 : */
107 75225 : bool ShouldLog(LogLevel aLevel) const { return mLevel >= aLevel; }
108 :
109 : /**
110 : * Retrieves the log module's current level.
111 : */
112 1110 : LogLevel Level() const { return mLevel; }
113 :
114 : /**
115 : * Sets the log module's level.
116 : */
117 3 : void SetLevel(LogLevel level) { mLevel = level; }
118 :
119 : /**
120 : * Print a log message for this module.
121 : */
122 : void Printv(LogLevel aLevel, const char* aFmt, va_list aArgs) const MOZ_FORMAT_PRINTF(3, 0);
123 :
124 : /**
125 : * Retrieves the module name.
126 : */
127 0 : const char* Name() const { return mName; }
128 :
129 : private:
130 : friend class LogModuleManager;
131 :
132 182 : explicit LogModule(const char* aName, LogLevel aLevel)
133 182 : : mName(strdup(aName)), mLevel(aLevel)
134 : {
135 182 : }
136 :
137 : LogModule(LogModule&) = delete;
138 : LogModule& operator=(const LogModule&) = delete;
139 :
140 : char* mName;
141 : Atomic<LogLevel, Relaxed> mLevel;
142 : };
143 :
144 : /**
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.
148 : *
149 : * Example usage:
150 : * static LazyLogModule sLayoutLog("layout");
151 : *
152 : * void Foo() {
153 : * MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
154 : * }
155 : */
156 : class LazyLogModule final
157 : {
158 : public:
159 : explicit constexpr LazyLogModule(const char* aLogName)
160 : : mLogName(aLogName)
161 : , mLog(nullptr)
162 : {
163 : }
164 :
165 75694 : operator LogModule*()
166 : {
167 : // NB: The use of an atomic makes the reading and assignment of mLog
168 : // thread-safe. There is a small chance that mLog will be set more
169 : // than once, but that's okay as it will be set to the same LogModule
170 : // instance each time. Also note LogModule::Get is thread-safe.
171 75694 : LogModule* tmp = mLog;
172 75691 : if (MOZ_UNLIKELY(!tmp)) {
173 186 : tmp = LogModule::Get(mLogName);
174 186 : mLog = tmp;
175 : }
176 :
177 75690 : return tmp;
178 : }
179 :
180 : private:
181 : const char* const mLogName;
182 : Atomic<LogModule*, ReleaseAcquire> mLog;
183 : };
184 :
185 : namespace detail {
186 :
187 75226 : inline bool log_test(const LogModule* module, LogLevel level) {
188 75226 : MOZ_ASSERT(level != LogLevel::Disabled);
189 75226 : return module && module->ShouldLog(level);
190 : }
191 :
192 : void log_print(const LogModule* aModule,
193 : LogLevel aLevel,
194 : const char* aFmt, ...) MOZ_FORMAT_PRINTF(3, 4);
195 : } // namespace detail
196 :
197 : } // namespace mozilla
198 :
199 :
200 : // Helper macro used convert MOZ_LOG's third parameter, |_args|, from a
201 : // parenthesized form to a varargs form. For example:
202 : // ("%s", "a message") => "%s", "a message"
203 : #define MOZ_LOG_EXPAND_ARGS(...) __VA_ARGS__
204 :
205 : #if MOZ_LOGGING_ENABLED
206 : #define MOZ_LOG_TEST(_module,_level) mozilla::detail::log_test(_module, _level)
207 : #else
208 : // Define away MOZ_LOG_TEST here so the compiler will fold away entire
209 : // logging blocks via dead code elimination, e.g.:
210 : //
211 : // if (MOZ_LOG_TEST(...)) {
212 : // ...compute things to log and log them...
213 : // }
214 : //
215 : // This also has the nice property that no special definition of MOZ_LOG is
216 : // required when logging is disabled.
217 : #define MOZ_LOG_TEST(_module,_level) false
218 : #endif
219 :
220 : #define MOZ_LOG(_module,_level,_args) \
221 : do { \
222 : if (MOZ_LOG_TEST(_module,_level)) { \
223 : mozilla::detail::log_print(_module, _level, MOZ_LOG_EXPAND_ARGS _args); \
224 : } \
225 : } while (0)
226 :
227 : // This #define is a Logging.h-only knob! Don't encourage people to get fancy
228 : // with their log definitions by exporting it outside of Logging.h.
229 : #undef MOZ_LOGGING_ENABLED
230 :
231 : #endif // mozilla_logging_h
|