blob: 244d6a9939f1c060adaf11aa926f15efbf1ec4f3 [file] [log] [blame] [edit]
// Copyright 2006-2008 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MINI_CHROMIUM_BASE_LOGGING_H_
#define MINI_CHROMIUM_BASE_LOGGING_H_
#include <errno.h>
#include <stdint.h>
#include <limits>
#include <sstream>
#include <string>
#include "build/build_config.h"
namespace logging {
// A bitmask of potential logging destinations.
using LoggingDestination = uint32_t;
// Specifies where logs will be written. Multiple destinations can be specified
// with bitwise OR.
// Unless destination is LOG_NONE, all logs with severity ERROR and above will
// be written to stderr in addition to the specified destination.
enum : LoggingDestination {
LOG_NONE = 0,
LOG_TO_FILE = 1 << 0,
LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1,
LOG_TO_STDERR = 1 << 2,
LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG | LOG_TO_STDERR,
#if BUILDFLAG(IS_WIN)
LOG_DEFAULT = LOG_TO_FILE,
#elif BUILDFLAG(IS_FUCHSIA)
LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG,
#elif BUILDFLAG(IS_POSIX)
LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG | LOG_TO_STDERR,
#endif
};
struct LoggingSettings {
LoggingDestination logging_dest = LOG_DEFAULT;
};
// Sets the logging destination.
//
// TODO(jperaza): LOG_TO_FILE is not yet supported.
bool InitLogging(const LoggingSettings& settings);
typedef int LogSeverity;
const LogSeverity LOG_VERBOSE = -1;
const LogSeverity LOG_INFO = 0;
const LogSeverity LOG_WARNING = 1;
const LogSeverity LOG_ERROR = 2;
const LogSeverity LOG_ERROR_REPORT = 3;
const LogSeverity LOG_FATAL = 4;
const LogSeverity LOG_NUM_SEVERITIES = 5;
#if defined(NDEBUG)
const LogSeverity LOG_DFATAL = LOG_ERROR;
#else
const LogSeverity LOG_DFATAL = LOG_FATAL;
#endif
typedef bool (*LogMessageHandlerFunction)(LogSeverity severity,
const char* file_poath,
int line,
size_t message_start,
const std::string& string);
void SetLogMessageHandler(LogMessageHandlerFunction log_message_handler);
LogMessageHandlerFunction GetLogMessageHandler();
static inline int GetMinLogLevel() {
return LOG_INFO;
}
static inline int GetVlogLevel(const char*) {
return std::numeric_limits<int>::max();
}
#if BUILDFLAG(IS_WIN)
// This is just ::GetLastError, but out-of-line to avoid including windows.h in
// such a widely used place.
unsigned long GetLastSystemErrorCode();
std::string SystemErrorCodeToString(unsigned long error_code);
#elif BUILDFLAG(IS_POSIX)
static inline int GetLastSystemErrorCode() {
return errno;
}
#endif
class LogMessage {
public:
LogMessage(const char* function,
const char* file_path,
int line,
LogSeverity severity);
LogMessage(const char* function,
const char* file_path,
int line,
std::string* result);
LogMessage(const LogMessage&) = delete;
LogMessage& operator=(const LogMessage&) = delete;
virtual ~LogMessage();
std::ostream& stream() { return stream_; }
protected:
void Flush();
private:
void Init(const char* function);
std::ostringstream stream_;
const char* file_path_;
size_t message_start_;
const int line_;
LogSeverity severity_;
};
class LogMessageFatal final : public LogMessage {
public:
using LogMessage::LogMessage;
[[noreturn]] ~LogMessageFatal() override;
};
#if BUILDFLAG(IS_WIN)
class Win32ErrorLogMessage : public LogMessage {
public:
Win32ErrorLogMessage(const char* function,
const char* file_path,
int line,
LogSeverity severity,
unsigned long err);
Win32ErrorLogMessage(const Win32ErrorLogMessage&) = delete;
Win32ErrorLogMessage& operator=(const Win32ErrorLogMessage&) = delete;
~Win32ErrorLogMessage();
protected:
void AppendError();
private:
unsigned long err_;
};
class Win32ErrorLogMessageFatal final : public Win32ErrorLogMessage {
public:
using Win32ErrorLogMessage::Win32ErrorLogMessage;
[[noreturn]] ~Win32ErrorLogMessageFatal() override;
};
#elif BUILDFLAG(IS_POSIX)
class ErrnoLogMessage : public LogMessage {
public:
ErrnoLogMessage(const char* function,
const char* file_path,
int line,
LogSeverity severity,
int err);
ErrnoLogMessage(const ErrnoLogMessage&) = delete;
ErrnoLogMessage& operator=(const ErrnoLogMessage&) = delete;
~ErrnoLogMessage();
protected:
void AppendError();
private:
int err_;
};
class ErrnoLogMessageFatal final : public ErrnoLogMessage {
public:
using ErrnoLogMessage::ErrnoLogMessage;
[[noreturn]] ~ErrnoLogMessageFatal() override;
};
#endif
} // namespace logging
#if defined(COMPILER_MSVC)
#define FUNCTION_SIGNATURE __FUNCSIG__
#else
#define FUNCTION_SIGNATURE __PRETTY_FUNCTION__
#endif
#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
logging::ClassName(FUNCTION_SIGNATURE, __FILE__, __LINE__, \
logging::LOG_INFO, ## __VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
logging::ClassName(FUNCTION_SIGNATURE, __FILE__, __LINE__, \
logging::LOG_WARNING, ## __VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
logging::ClassName(FUNCTION_SIGNATURE, __FILE__, __LINE__, \
logging::LOG_ERROR, ## __VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName, ...) \
logging::ClassName(FUNCTION_SIGNATURE, __FILE__, __LINE__, \
logging::LOG_ERROR_REPORT, ## __VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
logging::ClassName##Fatal(FUNCTION_SIGNATURE, \
__FILE__, \
__LINE__, \
logging::LOG_FATAL, \
##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
logging::ClassName(FUNCTION_SIGNATURE, __FILE__, __LINE__, \
logging::LOG_DFATAL, ## __VA_ARGS__)
#define COMPACT_GOOGLE_LOG_INFO \
COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
#define COMPACT_GOOGLE_LOG_WARNING \
COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
#define COMPACT_GOOGLE_LOG_ERROR \
COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
#define COMPACT_GOOGLE_LOG_ERROR_REPORT \
COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(LogMessage)
// TODO(crbug.com/40254046): Make LOG(FATAL) understood as [[noreturn]]. See
// Chromium or absl implementations for LogMessageFatal subclasses where the
// destructor is annotated as [[noreturn]].
#define COMPACT_GOOGLE_LOG_FATAL \
COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
#define COMPACT_GOOGLE_LOG_DFATAL \
COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
#if BUILDFLAG(IS_WIN)
// wingdi.h defines ERROR 0. We don't want to include windows.h here, and we
// want to allow "LOG(ERROR)", which will expand to LOG_0.
// This will not cause a warning if the RHS text is identical to that in
// wingdi.h (which it is).
#define ERROR 0
#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
namespace logging {
const LogSeverity LOG_0 = LOG_ERROR;
} // namespace logging
#endif // BUILDFLAG(IS_WIN)
#define LAZY_STREAM(stream, condition) \
switch (0) \
case 0: \
default: \
if (!(condition)) \
; \
else \
(stream)
// FATAL is always enabled and required to be resolved in compile time for
// LOG(FATAL) to be properly understood as [[noreturn]].
#define LOG_IS_ON(severity) \
((::logging::LOG_##severity) == ::logging::LOG_FATAL || \
(::logging::LOG_##severity) >= ::logging::GetMinLogLevel())
#define VLOG_IS_ON(verbose_level) \
((verbose_level) <= ::logging::GetVlogLevel(__FILE__))
#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
#define VLOG_STREAM(verbose_level) \
logging::LogMessage(FUNCTION_SIGNATURE, __FILE__, __LINE__, \
-verbose_level).stream()
#if BUILDFLAG(IS_WIN)
#define PLOG_STREAM(severity) COMPACT_GOOGLE_LOG_EX_ ## severity( \
Win32ErrorLogMessage, ::logging::GetLastSystemErrorCode()).stream()
#define VPLOG_STREAM(verbose_level) \
logging::Win32ErrorLogMessage(FUNCTION_SIGNATURE, __FILE__, __LINE__, \
-verbose_level, \
::logging::GetLastSystemErrorCode()).stream()
#elif BUILDFLAG(IS_POSIX)
#define PLOG_STREAM(severity) COMPACT_GOOGLE_LOG_EX_ ## severity( \
ErrnoLogMessage, ::logging::GetLastSystemErrorCode()).stream()
#define VPLOG_STREAM(verbose_level) \
logging::ErrnoLogMessage(FUNCTION_SIGNATURE, __FILE__, __LINE__, \
-verbose_level, \
::logging::GetLastSystemErrorCode()).stream()
#endif
#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
#define LOG_IF(severity, condition) \
LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
#define LOG_ASSERT(condition) \
LOG_IF(FATAL, !(condition)) << "Assertion failed: " # condition ". "
#define VLOG(verbose_level) \
LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
#define VLOG_IF(verbose_level, condition) \
LAZY_STREAM(VLOG_STREAM(verbose_level), \
VLOG_IS_ON(verbose_level) && (condition))
#define PLOG(severity) LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity))
#define PLOG_IF(severity, condition) \
LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
#define VPLOG(verbose_level) \
LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
#define VPLOG_IF(verbose_level, condition) \
LAZY_STREAM(VPLOG_STREAM(verbose_level), \
VLOG_IS_ON(verbose_level) && (condition))
#if defined(NDEBUG)
#define DLOG_IS_ON(severity) 0
#define DVLOG_IS_ON(verbose_level) 0
#define DCHECK_IS_ON() 0
#else
#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
#define DVLOG_IS_ON(verbose_level) VLOG_IS_ON(verbose_level)
#define DCHECK_IS_ON() 1
#endif
#define DLOG(severity) LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
#define DLOG_IF(severity, condition) \
LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity) && (condition))
#define DLOG_ASSERT(condition) \
DLOG_IF(FATAL, !(condition)) << "Assertion failed: " # condition ". "
#define DVLOG(verbose_level) \
LAZY_STREAM(VLOG_STREAM(verbose_level), DVLOG_IS_ON(verbose_level))
#define DVLOG_IF(verbose_level, condition) \
LAZY_STREAM(VLOG_STREAM(verbose_level), \
DVLOG_IS_ON(verbose_level) && (condition))
#define DPLOG(severity) LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity))
#define DPLOG_IF(severity, condition) \
LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity) && (condition))
#define DVPLOG(verbose_level) \
LAZY_STREAM(VPLOG_STREAM(verbose_level), DVLOG_IS_ON(verbose_level))
#define DVPLOG_IF(verbose_level, condition) \
LAZY_STREAM(VPLOG_STREAM(verbose_level), \
DVLOG_IS_ON(verbose_level) && (condition))
namespace std {
ostream& operator<<(ostream& out, const u16string& str);
} // namespace std
#endif // MINI_CHROMIUM_BASE_LOGGING_H_