Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b547c85b authored by Dan Albert's avatar Dan Albert
Browse files

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
parent ea975880
Loading
Loading
Loading
Loading
+45 −15
Original line number Diff line number Diff line
@@ -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();
@@ -66,7 +96,7 @@ extern const char* ProgramInvocationShortName();
//
//     LOG(FATAL) << "We didn't expect to reach here";
#define LOG(severity)                                                       \
  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::MAIN, \
  ::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
@@ -78,7 +108,7 @@ 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, \
  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
                              ::android::base::severity, errno).stream()

// Behaves like PLOG, but logs to the specified log ID.
@@ -98,7 +128,7 @@ extern const char* ProgramInvocationShortName();
//       "Check failed: false == true".
#define CHECK(x)                                                            \
  if (UNLIKELY(!(x)))                                                       \
  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::MAIN, \
  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
                              ::android::base::FATAL, -1).stream()          \
      << "Check failed: " #x << " "

@@ -107,7 +137,7 @@ extern const char* ProgramInvocationShortName();
  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::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
                              ::android::base::FATAL, -1).stream()          \
      << "Check failed: " << #LHS << " " << #OP << " " << #RHS              \
      << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
+78 −46
Original line number Diff line number Diff line
@@ -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,9 +258,6 @@ 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) {
    LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
            data_->GetSeverity(), msg.c_str());
@@ -211,7 +272,6 @@ LogMessage::~LogMessage() {
      i = nl + 1;
    }
  }
  }

  // Abort if necessary.
  if (data_->GetSeverity() == FATAL) {
@@ -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) {
+4 −4
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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();
}