summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorDan Albert <danalbert@google.com>2015-03-27 11:20:14 -0700
committerDan Albert <danalbert@google.com>2015-04-03 16:22:39 -0700
commitb547c85b5b9d7fc565e47a5d0c734c3a66af242a (patch)
tree1e9490de3134c6383da548f15186ae9f13ea5b1b /base
parentea975880112c27293800ede36e0323ff2a7b9322 (diff)
downloadsystem_core-b547c85b5b9d7fc565e47a5d0c734c3a66af242a.zip
system_core-b547c85b5b9d7fc565e47a5d0c734c3a66af242a.tar.gz
system_core-b547c85b5b9d7fc565e47a5d0c734c3a66af242a.tar.bz2
Support arbitrary loggers.
While the defaults (logd or stderr) make sense for most use cases, there are places that can only log to the kernel, or need to log to a file, etc. Allow the user to pass in an arbitrary logging object, and provide LogdLogger and StderrLogger as defaults. Change-Id: I62368acc795ff313242bb205d65017404bf64e88
Diffstat (limited to 'base')
-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();
}