• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_LOGGING_H_
6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_LOGGING_H_
7 
8 #include <stddef.h>
9 
10 #include <cassert>
11 #include <cstdint>
12 #include <sstream>
13 #include <string>
14 
15 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
16 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
17 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
18 #include "base/allocator/partition_allocator/partition_alloc_base/scoped_clear_last_error.h"
19 #include "build/build_config.h"
20 
21 // TODO(1151236): Need to update the description, because logging for PA
22 // standalone library was minimized.
23 //
24 // Optional message capabilities
25 // -----------------------------
26 // Assertion failed messages and fatal errors are displayed in a dialog box
27 // before the application exits. However, running this UI creates a message
28 // loop, which causes application messages to be processed and potentially
29 // dispatched to existing application windows. Since the application is in a
30 // bad state when this assertion dialog is displayed, these messages may not
31 // get processed and hang the dialog, or the application might go crazy.
32 //
33 // Therefore, it can be beneficial to display the error dialog in a separate
34 // process from the main application. When the logging system needs to display
35 // a fatal error dialog box, it will look for a program called
36 // "DebugMessage.exe" in the same directory as the application executable. It
37 // will run this application with the message as the command line, and will
38 // not include the name of the application as is traditional for easier
39 // parsing.
40 //
41 // The code for DebugMessage.exe is only one line. In WinMain, do:
42 //   MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
43 //
44 // If DebugMessage.exe is not found, the logging code will use a normal
45 // MessageBox, potentially causing the problems discussed above.
46 
47 // Instructions
48 // ------------
49 //
50 // Make a bunch of macros for logging.  The way to log things is to stream
51 // things to PA_LOG(<a particular severity level>).  E.g.,
52 //
53 //   PA_LOG(INFO) << "Found " << num_cookies << " cookies";
54 //
55 // You can also do conditional logging:
56 //
57 //   PA_LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
58 //
59 // The CHECK(condition) macro is active in both debug and release builds and
60 // effectively performs a PA_LOG(FATAL) which terminates the process and
61 // generates a crashdump unless a debugger is attached.
62 //
63 // There are also "debug mode" logging macros like the ones above:
64 //
65 //   PA_DLOG(INFO) << "Found cookies";
66 //
67 //   PA_DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
68 //
69 // All "debug mode" logging is compiled away to nothing for non-debug mode
70 // compiles.  PA_LOG_IF and development flags also work well together
71 // because the code can be compiled away sometimes.
72 //
73 // We also have
74 //
75 //   PA_LOG_ASSERT(assertion);
76 //   PA_DLOG_ASSERT(assertion);
77 //
78 // which is syntactic sugar for PA_{,D}LOG_IF(FATAL, assert fails) << assertion;
79 //
80 // There are "verbose level" logging macros.  They look like
81 //
82 //   PA_VLOG(1) << "I'm printed when you run the program with --v=1 or more";
83 //   PA_VLOG(2) << "I'm printed when you run the program with --v=2 or more";
84 //
85 // These always log at the INFO log level (when they log at all).
86 //
87 // There's also PA_VLOG_IS_ON(n) "verbose level" condition macro. To be used as
88 //
89 //   if (PA_VLOG_IS_ON(2)) {
90 //     // do some logging preparation and logging
91 //     // that can't be accomplished with just PA_VLOG(2) << ...;
92 //   }
93 //
94 // There is also a PA_VLOG_IF "verbose level" condition macro for sample
95 // cases, when some extra computation and preparation for logs is not
96 // needed.
97 //
98 //   PA_VLOG_IF(1, (size > 1024))
99 //      << "I'm printed when size is more than 1024 and when you run the "
100 //         "program with --v=1 or more";
101 //
102 // We also override the standard 'assert' to use 'PA_DLOG_ASSERT'.
103 //
104 // Lastly, there is:
105 //
106 //   PA_PLOG(ERROR) << "Couldn't do foo";
107 //   PA_DPLOG(ERROR) << "Couldn't do foo";
108 //   PA_PLOG_IF(ERROR, cond) << "Couldn't do foo";
109 //   PA_DPLOG_IF(ERROR, cond) << "Couldn't do foo";
110 //   PA_PCHECK(condition) << "Couldn't do foo";
111 //   PA_DPCHECK(condition) << "Couldn't do foo";
112 //
113 // which append the last system error to the message in string form (taken from
114 // GetLastError() on Windows and errno on POSIX).
115 //
116 // The supported severity levels for macros that allow you to specify one
117 // are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
118 //
119 // Very important: logging a message at the FATAL severity level causes
120 // the program to terminate (after the message is logged).
121 //
122 // There is the special severity of DFATAL, which logs FATAL in DCHECK-enabled
123 // builds, ERROR in normal mode.
124 //
125 // Output is formatted as per the following example:
126 // [VERBOSE1:drm_device_handle.cc(90)] Succeeded
127 // authenticating /dev/dri/card0 in 0 ms with 1 attempt(s)
128 //
129 // The colon separated fields inside the brackets are as follows:
130 // 1. The log level
131 // 2. The filename and line number where the log was instantiated
132 //
133 // Additional logging-related information can be found here:
134 // https://chromium.googlesource.com/chromium/src/+/main/docs/linux/debugging.md#Logging
135 
136 namespace partition_alloc::internal::logging {
137 
138 // Sets the log level. Anything at or above this level will be written to the
139 // log file/displayed to the user (if applicable). Anything below this level
140 // will be silently ignored. The log level defaults to 0 (everything is logged
141 // up to level INFO) if this function is not called.
142 // Note that log messages for VLOG(x) are logged at level -x, so setting
143 // the min log level to negative values enables verbose logging.
144 PA_COMPONENT_EXPORT(PARTITION_ALLOC) void SetMinLogLevel(int level);
145 
146 // Gets the current log level.
147 PA_COMPONENT_EXPORT(PARTITION_ALLOC) int GetMinLogLevel();
148 
149 // Used by PA_LOG_IS_ON to lazy-evaluate stream arguments.
150 PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool ShouldCreateLogMessage(int severity);
151 
152 // Gets the PA_VLOG default verbosity level.
153 PA_COMPONENT_EXPORT(PARTITION_ALLOC) int GetVlogVerbosity();
154 
155 // Sets the Log Message Handler that gets passed every log message before
156 // it's sent to other log destinations (if any).
157 // Returns true to signal that it handled the message and the message
158 // should not be sent to other log destinations.
159 typedef bool (*LogMessageHandlerFunction)(int severity,
160                                           const char* file,
161                                           int line,
162                                           size_t message_start,
163                                           const std::string& str);
164 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
165 void SetLogMessageHandler(LogMessageHandlerFunction handler);
166 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
167 LogMessageHandlerFunction GetLogMessageHandler();
168 
169 using LogSeverity = int;
170 constexpr LogSeverity LOGGING_VERBOSE = -1;  // This is level 1 verbosity
171 // Note: the log severities are used to index into the array of names,
172 // see log_severity_names.
173 constexpr LogSeverity LOGGING_INFO = 0;
174 constexpr LogSeverity LOGGING_WARNING = 1;
175 constexpr LogSeverity LOGGING_ERROR = 2;
176 constexpr LogSeverity LOGGING_FATAL = 3;
177 constexpr LogSeverity LOGGING_NUM_SEVERITIES = 4;
178 
179 // LOGGING_DFATAL is LOGGING_FATAL in DCHECK-enabled builds, ERROR in normal
180 // mode.
181 #if BUILDFLAG(PA_DCHECK_IS_ON)
182 constexpr LogSeverity LOGGING_DFATAL = LOGGING_FATAL;
183 #else
184 constexpr LogSeverity LOGGING_DFATAL = LOGGING_ERROR;
185 #endif
186 
187 // This block duplicates the above entries to facilitate incremental conversion
188 // from LOG_FOO to LOGGING_FOO.
189 // TODO(thestig): Convert existing users to LOGGING_FOO and remove this block.
190 constexpr LogSeverity LOG_VERBOSE = LOGGING_VERBOSE;
191 constexpr LogSeverity LOG_INFO = LOGGING_INFO;
192 constexpr LogSeverity LOG_WARNING = LOGGING_WARNING;
193 constexpr LogSeverity LOG_ERROR = LOGGING_ERROR;
194 constexpr LogSeverity LOG_FATAL = LOGGING_FATAL;
195 constexpr LogSeverity LOG_DFATAL = LOGGING_DFATAL;
196 
197 // A few definitions of macros that don't generate much code. These are used
198 // by PA_LOG() and LOG_IF, etc. Since these are used all over our code, it's
199 // better to have compact code for these operations.
200 #define PA_COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...)                         \
201   ::partition_alloc::internal::logging::ClassName(                            \
202       __FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_INFO, \
203       ##__VA_ARGS__)
204 #define PA_COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
205   ::partition_alloc::internal::logging::ClassName(       \
206       __FILE__, __LINE__,                                \
207       ::partition_alloc::internal::logging::LOGGING_WARNING, ##__VA_ARGS__)
208 #define PA_COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...)                         \
209   ::partition_alloc::internal::logging::ClassName(                             \
210       __FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_ERROR, \
211       ##__VA_ARGS__)
212 #define PA_COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...)                         \
213   ::partition_alloc::internal::logging::ClassName(                             \
214       __FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_FATAL, \
215       ##__VA_ARGS__)
216 #define PA_COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
217   ::partition_alloc::internal::logging::ClassName(      \
218       __FILE__, __LINE__,                               \
219       ::partition_alloc::internal::logging::LOGGING_DFATAL, ##__VA_ARGS__)
220 #define PA_COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
221   ::partition_alloc::internal::logging::ClassName(      \
222       __FILE__, __LINE__,                               \
223       ::partition_alloc::internal::logging::LOGGING_DCHECK, ##__VA_ARGS__)
224 
225 #define PA_COMPACT_GOOGLE_LOG_INFO PA_COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
226 #define PA_COMPACT_GOOGLE_LOG_WARNING \
227   PA_COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
228 #define PA_COMPACT_GOOGLE_LOG_ERROR PA_COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
229 #define PA_COMPACT_GOOGLE_LOG_FATAL PA_COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
230 #define PA_COMPACT_GOOGLE_LOG_DFATAL PA_COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
231 #define PA_COMPACT_GOOGLE_LOG_DCHECK PA_COMPACT_GOOGLE_LOG_EX_DCHECK(LogMessage)
232 
233 #if BUILDFLAG(IS_WIN)
234 // wingdi.h defines ERROR to be 0. When we call PA_LOG(ERROR), it gets
235 // substituted with 0, and it expands to PA_COMPACT_GOOGLE_LOG_0. To allow us
236 // to keep using this syntax, we define this macro to do the same thing
237 // as PA_COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
238 // the Windows SDK does for consistency.
239 #define PA_ERROR 0
240 #define PA_COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
241   PA_COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ##__VA_ARGS__)
242 #define PA_COMPACT_GOOGLE_LOG_0 PA_COMPACT_GOOGLE_LOG_ERROR
243 // Needed for LOG_IS_ON(ERROR).
244 constexpr LogSeverity LOGGING_0 = LOGGING_ERROR;
245 #endif
246 
247 // As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
248 // LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
249 // always fire if they fail.
250 #define PA_LOG_IS_ON(severity)                                   \
251   (::partition_alloc::internal::logging::ShouldCreateLogMessage( \
252       ::partition_alloc::internal::logging::LOGGING_##severity))
253 
254 // We don't do any caching tricks with VLOG_IS_ON() like the
255 // google-glog version since it increases binary size.  This means
256 // that using the v-logging functions in conjunction with --vmodule
257 // may be slow.
258 #define PA_VLOG_IS_ON(verboselevel) \
259   ((verboselevel) <= ::partition_alloc::internal::logging::GetVlogVerbosity())
260 
261 // Helper macro which avoids evaluating the arguments to a stream if
262 // the condition doesn't hold. Condition is evaluated once and only once.
263 #define PA_LAZY_STREAM(stream, condition) \
264   !(condition)                            \
265       ? (void)0                           \
266       : ::partition_alloc::internal::logging::LogMessageVoidify() & (stream)
267 
268 // We use the preprocessor's merging operator, "##", so that, e.g.,
269 // PA_LOG(INFO) becomes the token PA_COMPACT_GOOGLE_LOG_INFO.  There's some
270 // funny subtle difference between ostream member streaming functions (e.g.,
271 // ostream::operator<<(int) and ostream non-member streaming functions
272 // (e.g., ::operator<<(ostream&, string&): it turns out that it's
273 // impossible to stream something like a string directly to an unnamed
274 // ostream. We employ a neat hack by calling the stream() member
275 // function of LogMessage which seems to avoid the problem.
276 #define PA_LOG_STREAM(severity) PA_COMPACT_GOOGLE_LOG_##severity.stream()
277 
278 #define PA_LOG(severity) \
279   PA_LAZY_STREAM(PA_LOG_STREAM(severity), PA_LOG_IS_ON(severity))
280 #define PA_LOG_IF(severity, condition) \
281   PA_LAZY_STREAM(PA_LOG_STREAM(severity), PA_LOG_IS_ON(severity) && (condition))
282 
283 // The VLOG macros log with negative verbosities.
284 #define PA_VLOG_STREAM(verbose_level)                                  \
285   ::partition_alloc::internal::logging::LogMessage(__FILE__, __LINE__, \
286                                                    -(verbose_level))   \
287       .stream()
288 
289 #define PA_VLOG(verbose_level) \
290   PA_LAZY_STREAM(PA_VLOG_STREAM(verbose_level), PA_VLOG_IS_ON(verbose_level))
291 
292 #define PA_VLOG_IF(verbose_level, condition)    \
293   PA_LAZY_STREAM(PA_VLOG_STREAM(verbose_level), \
294                  PA_VLOG_IS_ON(verbose_level) && (condition))
295 
296 #if BUILDFLAG(IS_WIN)
297 #define PA_VPLOG_STREAM(verbose_level)                                \
298   ::partition_alloc::internal::logging::Win32ErrorLogMessage(         \
299       __FILE__, __LINE__, -(verbose_level),                           \
300       ::partition_alloc::internal::logging::GetLastSystemErrorCode()) \
301       .stream()
302 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
303 #define PA_VPLOG_STREAM(verbose_level)                                \
304   ::partition_alloc::internal::logging::ErrnoLogMessage(              \
305       __FILE__, __LINE__, -(verbose_level),                           \
306       ::partition_alloc::internal::logging::GetLastSystemErrorCode()) \
307       .stream()
308 #endif
309 
310 #define PA_VPLOG(verbose_level) \
311   PA_LAZY_STREAM(PA_VPLOG_STREAM(verbose_level), PA_VLOG_IS_ON(verbose_level))
312 
313 #define PA_VPLOG_IF(verbose_level, condition)    \
314   PA_LAZY_STREAM(PA_VPLOG_STREAM(verbose_level), \
315                  PA_VLOG_IS_ON(verbose_level) && (condition))
316 
317 // TODO(akalin): Add more VLOG variants, e.g. VPLOG.
318 
319 #define PA_LOG_ASSERT(condition)                          \
320   PA_LOG_IF(FATAL, !(PA_ANALYZER_ASSUME_TRUE(condition))) \
321       << "Assert failed: " #condition ". "
322 
323 #if BUILDFLAG(IS_WIN)
324 #define PA_PLOG_STREAM(severity)                                      \
325   PA_COMPACT_GOOGLE_LOG_EX_##severity(                                \
326       Win32ErrorLogMessage,                                           \
327       ::partition_alloc::internal::logging::GetLastSystemErrorCode()) \
328       .stream()
329 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
330 #define PA_PLOG_STREAM(severity)                                      \
331   PA_COMPACT_GOOGLE_LOG_EX_##severity(                                \
332       ErrnoLogMessage,                                                \
333       ::partition_alloc::internal::logging::GetLastSystemErrorCode()) \
334       .stream()
335 #endif
336 
337 #define PA_PLOG(severity) \
338   PA_LAZY_STREAM(PA_PLOG_STREAM(severity), PA_LOG_IS_ON(severity))
339 
340 #define PA_PLOG_IF(severity, condition)    \
341   PA_LAZY_STREAM(PA_PLOG_STREAM(severity), \
342                  PA_LOG_IS_ON(severity) && (condition))
343 
344 PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern std::ostream* g_swallow_stream;
345 
346 // Note that g_swallow_stream is used instead of an arbitrary PA_LOG() stream to
347 // avoid the creation of an object with a non-trivial destructor (LogMessage).
348 // On MSVC x86 (checked on 2015 Update 3), this causes a few additional
349 // pointless instructions to be emitted even at full optimization level, even
350 // though the : arm of the ternary operator is clearly never executed. Using a
351 // simpler object to be &'d with Voidify() avoids these extra instructions.
352 // Using a simpler POD object with a templated operator<< also works to avoid
353 // these instructions. However, this causes warnings on statically defined
354 // implementations of operator<<(std::ostream, ...) in some .cc files, because
355 // they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an
356 // ostream* also is not suitable, because some compilers warn of undefined
357 // behavior.
358 #define PA_EAT_STREAM_PARAMETERS                                     \
359   true ? (void)0                                                     \
360        : ::partition_alloc::internal::logging::LogMessageVoidify() & \
361              (*::partition_alloc::internal::logging::g_swallow_stream)
362 
363 // Definitions for DLOG et al.
364 
365 #if BUILDFLAG(PA_DCHECK_IS_ON)
366 
367 #define PA_DLOG_IS_ON(severity) PA_LOG_IS_ON(severity)
368 #define PA_DLOG_IF(severity, condition) PA_LOG_IF(severity, condition)
369 #define PA_DLOG_ASSERT(condition) PA_LOG_ASSERT(condition)
370 #define PA_DPLOG_IF(severity, condition) PA_PLOG_IF(severity, condition)
371 #define PA_DVLOG_IF(verboselevel, condition) PA_VLOG_IF(verboselevel, condition)
372 #define PA_DVPLOG_IF(verboselevel, condition) \
373   PA_VPLOG_IF(verboselevel, condition)
374 
375 #else  // BUILDFLAG(PA_DCHECK_IS_ON)
376 
377 // If !BUILDFLAG(PA_DCHECK_IS_ON), we want to avoid emitting any references to
378 // |condition| (which may reference a variable defined only if
379 // BUILDFLAG(PA_DCHECK_IS_ON)). Contrast this with DCHECK et al., which has
380 // different behavior.
381 
382 #define PA_DLOG_IS_ON(severity) false
383 #define PA_DLOG_IF(severity, condition) PA_EAT_STREAM_PARAMETERS
384 #define PA_DLOG_ASSERT(condition) PA_EAT_STREAM_PARAMETERS
385 #define PA_DPLOG_IF(severity, condition) PA_EAT_STREAM_PARAMETERS
386 #define PA_DVLOG_IF(verboselevel, condition) PA_EAT_STREAM_PARAMETERS
387 #define PA_DVPLOG_IF(verboselevel, condition) PA_EAT_STREAM_PARAMETERS
388 
389 #endif  // BUILDFLAG(PA_DCHECK_IS_ON)
390 
391 #define PA_DLOG(severity) \
392   PA_LAZY_STREAM(PA_LOG_STREAM(severity), PA_DLOG_IS_ON(severity))
393 
394 #define PA_DPLOG(severity) \
395   PA_LAZY_STREAM(PA_PLOG_STREAM(severity), PA_DLOG_IS_ON(severity))
396 
397 #define PA_DVLOG(verboselevel) PA_DVLOG_IF(verboselevel, true)
398 
399 #define PA_DVPLOG(verboselevel) PA_DVPLOG_IF(verboselevel, true)
400 
401 // Definitions for DCHECK et al.
402 
403 #if BUILDFLAG(PA_DCHECK_IS_CONFIGURABLE)
404 PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern LogSeverity LOGGING_DCHECK;
405 #else
406 constexpr LogSeverity LOGGING_DCHECK = LOGGING_FATAL;
407 #endif  // BUILDFLAG(PA_DCHECK_IS_CONFIGURABLE)
408 
409 // Redefine the standard assert to use our nice log files
410 #undef assert
411 #define assert(x) PA_DLOG_ASSERT(x)
412 
413 // This class more or less represents a particular log message.  You
414 // create an instance of LogMessage and then stream stuff to it.
415 // When you finish streaming to it, ~LogMessage is called and the
416 // full message gets streamed to the appropriate destination.
417 //
418 // You shouldn't actually use LogMessage's constructor to log things,
419 // though.  You should use the PA_LOG() macro (and variants thereof)
420 // above.
PA_COMPONENT_EXPORT(PARTITION_ALLOC)421 class PA_COMPONENT_EXPORT(PARTITION_ALLOC) LogMessage {
422  public:
423   // Used for PA_LOG(severity).
424   LogMessage(const char* file, int line, LogSeverity severity);
425 
426   // Used for CHECK().  Implied severity = LOGGING_FATAL.
427   LogMessage(const char* file, int line, const char* condition);
428   LogMessage(const LogMessage&) = delete;
429   LogMessage& operator=(const LogMessage&) = delete;
430   virtual ~LogMessage();
431 
432   std::ostream& stream() { return stream_; }
433 
434   LogSeverity severity() { return severity_; }
435   std::string str() { return stream_.str(); }
436 
437  private:
438   void Init(const char* file, int line);
439 
440   const LogSeverity severity_;
441   std::ostringstream stream_;
442   size_t message_start_;  // Offset of the start of the message (past prefix
443                           // info).
444   // The file and line information passed in to the constructor.
445   const char* const file_;
446   const int line_;
447 
448   // This is useful since the LogMessage class uses a lot of Win32 calls
449   // that will lose the value of GLE and the code that called the log function
450   // will have lost the thread error value when the log call returns.
451   base::ScopedClearLastError last_error_;
452 };
453 
454 // This class is used to explicitly ignore values in the conditional
455 // logging macros.  This avoids compiler warnings like "value computed
456 // is not used" and "statement has no effect".
457 class LogMessageVoidify {
458  public:
459   LogMessageVoidify() = default;
460   // This has to be an operator with a precedence lower than << but
461   // higher than ?:
462   void operator&(std::ostream&) {}
463 };
464 
465 #if BUILDFLAG(IS_WIN)
466 typedef unsigned long SystemErrorCode;
467 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
468 typedef int SystemErrorCode;
469 #endif
470 
471 // Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
472 // pull in windows.h just for GetLastError() and DWORD.
473 PA_COMPONENT_EXPORT(PARTITION_ALLOC) SystemErrorCode GetLastSystemErrorCode();
474 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
475 std::string SystemErrorCodeToString(SystemErrorCode error_code);
476 
477 #if BUILDFLAG(IS_WIN)
478 // Appends a formatted system message of the GetLastError() type.
PA_COMPONENT_EXPORT(PARTITION_ALLOC)479 class PA_COMPONENT_EXPORT(PARTITION_ALLOC) Win32ErrorLogMessage
480     : public LogMessage {
481  public:
482   Win32ErrorLogMessage(const char* file,
483                        int line,
484                        LogSeverity severity,
485                        SystemErrorCode err);
486   Win32ErrorLogMessage(const Win32ErrorLogMessage&) = delete;
487   Win32ErrorLogMessage& operator=(const Win32ErrorLogMessage&) = delete;
488   // Appends the error message before destructing the encapsulated class.
489   ~Win32ErrorLogMessage() override;
490 
491  private:
492   SystemErrorCode err_;
493 };
494 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
495 // Appends a formatted system message of the errno type
PA_COMPONENT_EXPORT(PARTITION_ALLOC)496 class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ErrnoLogMessage : public LogMessage {
497  public:
498   ErrnoLogMessage(const char* file,
499                   int line,
500                   LogSeverity severity,
501                   SystemErrorCode err);
502   ErrnoLogMessage(const ErrnoLogMessage&) = delete;
503   ErrnoLogMessage& operator=(const ErrnoLogMessage&) = delete;
504   // Appends the error message before destructing the encapsulated class.
505   ~ErrnoLogMessage() override;
506 
507  private:
508   SystemErrorCode err_;
509 };
510 #endif  // BUILDFLAG(IS_WIN)
511 
512 // Async signal safe logging mechanism.
513 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
514 void RawLog(int level, const char* message);
515 
516 #define PA_RAW_LOG(level, message)              \
517   ::partition_alloc::internal::logging::RawLog( \
518       ::partition_alloc::internal::logging::LOGGING_##level, message)
519 
520 }  // namespace partition_alloc::internal::logging
521 
522 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_LOGGING_H_
523