summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Albert <danalbert@google.com>2015-04-03 23:28:40 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2015-04-03 23:28:40 +0000
commitde0e80d20de68469f445d9c425f3e351048be7ea (patch)
treed5633496abc3a41e7e3ec9782a7408e81b32a3e6
parent7c1945254ea3ae6ddb7fafb7d1a03b347ec76c91 (diff)
parentf78ff16aeed0e997124dff594f1ddc193741a7b3 (diff)
downloadsystem_core-de0e80d20de68469f445d9c425f3e351048be7ea.zip
system_core-de0e80d20de68469f445d9c425f3e351048be7ea.tar.gz
system_core-de0e80d20de68469f445d9c425f3e351048be7ea.tar.bz2
am f78ff16a: Merge "Support arbitrary loggers."
* commit 'f78ff16aeed0e997124dff594f1ddc193741a7b3': Support arbitrary loggers.
-rw-r--r--base/include/base/logging.h60
-rw-r--r--base/logging.cpp124
-rw-r--r--base/logging_test.cpp8
-rw-r--r--base/test_main.cpp2
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();
}