diff options
-rw-r--r-- | base/include/base/logging.h | 60 | ||||
-rw-r--r-- | base/logging.cpp | 124 | ||||
-rw-r--r-- | base/logging_test.cpp | 8 | ||||
-rw-r--r-- | base/test_main.cpp | 2 |
4 files changed, 128 insertions, 66 deletions
diff --git a/base/include/base/logging.h b/base/include/base/logging.h index 3460997..19c1b64 100644 --- a/base/include/base/logging.h +++ b/base/include/base/logging.h @@ -17,6 +17,7 @@ #ifndef BASE_LOGGING_H #define BASE_LOGGING_H +#include <functional> #include <memory> #include <ostream> @@ -35,10 +36,32 @@ enum LogSeverity { }; enum LogId { + DEFAULT, MAIN, SYSTEM, }; +typedef std::function<void(LogId, LogSeverity, const char*, const char*, + unsigned int, const char*)> LogFunction; + +extern void StderrLogger(LogId, LogSeverity, const char*, const char*, + unsigned int, const char*); + +#ifdef __ANDROID__ +// We expose this even though it is the default because a user that wants to +// override the default log buffer will have to construct this themselves. +class LogdLogger { + public: + explicit LogdLogger(LogId default_log_id = android::base::MAIN); + + void operator()(LogId, LogSeverity, const char* tag, const char* file, + unsigned int line, const char* message); + + private: + LogId default_log_id_; +}; +#endif + // Configure logging based on ANDROID_LOG_TAGS environment variable. // We need to parse a string that looks like // @@ -47,8 +70,15 @@ enum LogId { // The tag (or '*' for the global level) comes first, followed by a colon and a // letter indicating the minimum priority level we're expected to log. This can // be used to reveal or conceal logs with specific tags. +extern void InitLogging(char* argv[], LogFunction&& logger); + +// Configures logging using the default logger (logd for the device, stderr for +// the host). extern void InitLogging(char* argv[]); +// Replace the current logger. +extern void SetLogger(LogFunction&& logger); + // Returns the command line used to invoke the current tool or nullptr if // InitLogging hasn't been performed. extern const char* GetCmdLine(); @@ -65,8 +95,8 @@ extern const char* ProgramInvocationShortName(); // FATAL it also causes an abort. For example: // // LOG(FATAL) << "We didn't expect to reach here"; -#define LOG(severity) \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::MAIN, \ +#define LOG(severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ ::android::base::severity, -1).stream() // Logs a message to logcat with the specified log ID on Android otherwise to @@ -77,8 +107,8 @@ extern const char* ProgramInvocationShortName(); // A variant of LOG that also logs the current errno value. To be used when // library calls fail. -#define PLOG(severity) \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::MAIN, \ +#define PLOG(severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ ::android::base::severity, errno).stream() // Behaves like PLOG, but logs to the specified log ID. @@ -96,20 +126,20 @@ extern const char* ProgramInvocationShortName(); // // CHECK(false == true) results in a log message of // "Check failed: false == true". -#define CHECK(x) \ - if (UNLIKELY(!(x))) \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::MAIN, \ - ::android::base::FATAL, -1).stream() \ +#define CHECK(x) \ + if (UNLIKELY(!(x))) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::FATAL, -1).stream() \ << "Check failed: " #x << " " // Helper for CHECK_xx(x,y) macros. -#define CHECK_OP(LHS, RHS, OP) \ - for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \ - UNLIKELY(!(_values.lhs OP _values.rhs)); \ - /* empty */) \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::MAIN, \ - ::android::base::FATAL, -1).stream() \ - << "Check failed: " << #LHS << " " << #OP << " " << #RHS \ +#define CHECK_OP(LHS, RHS, OP) \ + for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \ + UNLIKELY(!(_values.lhs OP _values.rhs)); \ + /* empty */) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::FATAL, -1).stream() \ + << "Check failed: " << #LHS << " " << #OP << " " << #RHS \ << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") " // Check whether a condition holds between x and y, LOG(FATAL) if not. The value diff --git a/base/logging.cpp b/base/logging.cpp index d2318cb..a36ac5f 100644 --- a/base/logging.cpp +++ b/base/logging.cpp @@ -21,6 +21,7 @@ #include <mutex> #include <sstream> #include <string> +#include <utility> #include <vector> #include "base/strings.h" @@ -40,6 +41,12 @@ namespace base { static std::mutex logging_lock; +#ifdef __ANDROID__ +static LogFunction gLogger = LogdLogger(); +#else +static LogFunction gLogger = StderrLogger; +#endif + static LogSeverity gMinimumLogSeverity = INFO; static std::unique_ptr<std::string> gCmdLine; static std::unique_ptr<std::string> gProgramInvocationName; @@ -61,6 +68,58 @@ const char* ProgramInvocationShortName() { : "unknown"; } +void StderrLogger(LogId, LogSeverity severity, const char*, const char* file, + unsigned int line, const char* message) { + static const char* log_characters = "VDIWEF"; + CHECK_EQ(strlen(log_characters), FATAL + 1U); + char severity_char = log_characters[severity]; + fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(), + severity_char, getpid(), gettid(), file, line, message); +} + + +#ifdef __ANDROID__ +LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) { +} + +static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { + ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, + ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, +}; +static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, + "Mismatch in size of kLogSeverityToAndroidLogPriority and values " + "in LogSeverity"); + +static const log_id kLogIdToAndroidLogId[] = { + LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM, +}; +static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1, + "Mismatch in size of kLogIdToAndroidLogId and values in LogId"); + +void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, + const char* file, unsigned int line, + const char* message) { + int priority = kLogSeverityToAndroidLogPriority[severity]; + if (id == DEFAULT) { + id = default_log_id_; + } + + log_id lg_id = kLogIdToAndroidLogId[id]; + + if (priority == ANDROID_LOG_FATAL) { + __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line, + message); + } else { + __android_log_buf_print(lg_id, priority, tag, "%s", message); + } +} +#endif + +void InitLogging(char* argv[], LogFunction&& logger) { + SetLogger(std::forward<LogFunction>(logger)); + InitLogging(argv); +} + void InitLogging(char* argv[]) { if (gCmdLine.get() != nullptr) { return; @@ -124,6 +183,11 @@ void InitLogging(char* argv[]) { } } +void SetLogger(LogFunction&& logger) { + std::lock_guard<std::mutex> lock(logging_lock); + gLogger = std::move(logger); +} + // This indirection greatly reduces the stack impact of having lots of // checks/logging in a function. class LogMessageData { @@ -194,22 +258,18 @@ LogMessage::~LogMessage() { } std::string msg(data_->ToString()); - // Do the actual logging with the lock held. - { - std::lock_guard<std::mutex> lock(logging_lock); - if (msg.find('\n') == std::string::npos) { + if (msg.find('\n') == std::string::npos) { + LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), + data_->GetSeverity(), msg.c_str()); + } else { + msg += '\n'; + size_t i = 0; + while (i < msg.size()) { + size_t nl = msg.find('\n', i); + msg[nl] = '\0'; LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), - data_->GetSeverity(), msg.c_str()); - } else { - msg += '\n'; - size_t i = 0; - while (i < msg.size()) { - size_t nl = msg.find('\n', i); - msg[nl] = '\0'; - LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), - data_->GetSeverity(), &msg[i]); - i = nl + 1; - } + data_->GetSeverity(), &msg[i]); + i = nl + 1; } } @@ -226,39 +286,11 @@ std::ostream& LogMessage::stream() { return data_->GetBuffer(); } -#ifdef __ANDROID__ -static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { - ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, - ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL}; -static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, - "Mismatch in size of kLogSeverityToAndroidLogPriority and values " - "in LogSeverity"); - -static const log_id kLogIdToAndroidLogId[] = {LOG_ID_MAIN, LOG_ID_SYSTEM}; -static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1, - "Mismatch in size of kLogIdToAndroidLogId and values " - "in LogSeverity"); -#endif - void LogMessage::LogLine(const char* file, unsigned int line, LogId id, - LogSeverity log_severity, const char* message) { -#ifdef __ANDROID__ + LogSeverity severity, const char* message) { const char* tag = ProgramInvocationShortName(); - int priority = kLogSeverityToAndroidLogPriority[log_severity]; - log_id lg_id = kLogIdToAndroidLogId[id]; - if (priority == ANDROID_LOG_FATAL) { - __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line, message); - } else { - __android_log_buf_print(lg_id, priority, tag, "%s", message); - } -#else - UNUSED(id); - static const char* log_characters = "VDIWEF"; - CHECK_EQ(strlen(log_characters), FATAL + 1U); - char severity = log_characters[log_severity]; - fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(), - severity, getpid(), gettid(), file, line, message); -#endif + std::lock_guard<std::mutex> lock(logging_lock); + gLogger(id, severity, tag, file, line, message); } ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { diff --git a/base/logging_test.cpp b/base/logging_test.cpp index 0a03e38..d947c1d 100644 --- a/base/logging_test.cpp +++ b/base/logging_test.cpp @@ -61,7 +61,7 @@ class CapturedStderr { int old_stderr_; }; -HOST_TEST(logging, CHECK) { +TEST(logging, CHECK) { ASSERT_DEATH(CHECK(false), "Check failed: false "); CHECK(true); @@ -82,7 +82,7 @@ std::string make_log_pattern(android::base::LogSeverity severity, log_char, message); } -HOST_TEST(logging, LOG) { +TEST(logging, LOG) { ASSERT_DEATH(LOG(FATAL) << "foobar", "foobar"); { @@ -136,7 +136,7 @@ HOST_TEST(logging, LOG) { } } -HOST_TEST(logging, PLOG) { +TEST(logging, PLOG) { { CapturedStderr cap; errno = ENOENT; @@ -152,7 +152,7 @@ HOST_TEST(logging, PLOG) { } } -HOST_TEST(logging, UNIMPLEMENTED) { +TEST(logging, UNIMPLEMENTED) { { CapturedStderr cap; errno = ENOENT; diff --git a/base/test_main.cpp b/base/test_main.cpp index c49ca4b..546923d 100644 --- a/base/test_main.cpp +++ b/base/test_main.cpp @@ -20,6 +20,6 @@ int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - android::base::InitLogging(argv); + android::base::InitLogging(argv, android::base::StderrLogger); return RUN_ALL_TESTS(); } |