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

Commit 1be0d148 authored by Elliott Hughes's avatar Elliott Hughes
Browse files

Add StdioLogger for command-line tools.

Bug: N/A
Test: ran tests
Change-Id: If366a4ea25aea1becdd3e443eba225e9bd52ebba
parent 9f6f8bf0
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -100,8 +100,17 @@ using LogFunction = std::function<void(LogId, LogSeverity, const char*, const ch
                                       unsigned int, const char*)>;
using AbortFunction = std::function<void(const char*)>;

// Loggers for use with InitLogging/SetLogger.

// Log to the kernel log (dmesg).
void KernelLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
// Log to stderr in the full logcat format (with pid/tid/time/tag details).
void StderrLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
// Log just the message to stdout/stderr (without pid/tid/time/tag details).
// The choice of stdout versus stderr is based on the severity.
// Errors are also prefixed by the program name (as with err(3)/error(3)).
// Useful for replacing printf(3)/perror(3)/err(3)/error(3) in command-line tools.
void StdioLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);

void DefaultAborter(const char* abort_message);

+19 −7
Original line number Diff line number Diff line
@@ -58,21 +58,33 @@ class TemporaryDir {
  DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
};

class CapturedStderr {
class CapturedStdFd {
 public:
  CapturedStderr();
  ~CapturedStderr();
  CapturedStdFd(int std_fd);
  ~CapturedStdFd();

  int fd() const;
  std::string str();

 private:
  void init();
  void reset();
  void Init();
  void Reset();

  TemporaryFile temp_file_;
  int old_stderr_;
  int std_fd_;
  int old_fd_;

  DISALLOW_COPY_AND_ASSIGN(CapturedStderr);
  DISALLOW_COPY_AND_ASSIGN(CapturedStdFd);
};

class CapturedStderr : public CapturedStdFd {
 public:
  CapturedStderr() : CapturedStdFd(STDERR_FILENO) {}
};

class CapturedStdout : public CapturedStdFd {
 public:
  CapturedStdout() : CapturedStdFd(STDOUT_FILENO) {}
};

#define ASSERT_MATCH(str, pattern)                                             \
+10 −0
Original line number Diff line number Diff line
@@ -212,6 +212,16 @@ void StderrLogger(LogId, LogSeverity severity, const char* tag, const char* file
          timestamp, getpid(), GetThreadId(), file, line, message);
}

void StdioLogger(LogId, LogSeverity severity, const char* /*tag*/, const char* /*file*/,
                 unsigned int /*line*/, const char* message) {
  if (severity >= WARNING) {
    fflush(stdout);
    fprintf(stderr, "%s: %s\n", getprogname(), message);
  } else {
    fprintf(stdout, "%s\n", message);
  }
}

void DefaultAborter(const char* abort_message) {
#ifdef __ANDROID__
  android_set_abort_message(abort_message);
+22 −4
Original line number Diff line number Diff line
@@ -206,11 +206,9 @@ static std::string make_log_pattern(android::base::LogSeverity severity,
}
#endif

static void CheckMessage(const CapturedStderr& cap, android::base::LogSeverity severity,
static void CheckMessage(CapturedStderr& cap, android::base::LogSeverity severity,
                         const char* expected, const char* expected_tag = nullptr) {
  std::string output;
  ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
  android::base::ReadFdToString(cap.fd(), &output);
  std::string output = cap.str();

  // We can't usefully check the output of any of these on Windows because we
  // don't have std::regex, but we can at least make sure we printed at least as
@@ -623,3 +621,23 @@ TEST(logging, SetDefaultTag) {
  }
  CheckMessage(cap, android::base::LogSeverity::INFO, expected_msg, expected_tag);
}

TEST(logging, StdioLogger) {
  std::string err_str;
  std::string out_str;
  {
    CapturedStderr cap_err;
    CapturedStdout cap_out;
    android::base::SetLogger(android::base::StdioLogger);
    LOG(INFO) << "out";
    LOG(ERROR) << "err";
    err_str = cap_err.str();
    out_str = cap_out.str();
  }

  // For INFO we expect just the literal "out\n".
  ASSERT_EQ("out\n", out_str) << out_str;
  // Whereas ERROR logging includes the program name.
  ASSERT_EQ(android::base::Basename(android::base::GetExecutablePath()) + ": err\n", err_str)
      << err_str;
}
+23 −14
Original line number Diff line number Diff line
@@ -14,7 +14,6 @@
 * limitations under the License.
 */

#include "android-base/logging.h"
#include "android-base/test_utils.h"

#include <fcntl.h>
@@ -33,6 +32,9 @@

#include <string>

#include <android-base/file.h>
#include <android-base/logging.h>

#ifdef _WIN32
int mkstemp(char* template_name) {
  if (_mktemp(template_name) == nullptr) {
@@ -123,31 +125,38 @@ bool TemporaryDir::init(const std::string& tmp_dir) {
  return (mkdtemp(path) != nullptr);
}

CapturedStderr::CapturedStderr() : old_stderr_(-1) {
  init();
CapturedStdFd::CapturedStdFd(int std_fd) : std_fd_(std_fd), old_fd_(-1) {
  Init();
}

CapturedStderr::~CapturedStderr() {
  reset();
CapturedStdFd::~CapturedStdFd() {
  Reset();
}

int CapturedStderr::fd() const {
int CapturedStdFd::fd() const {
  return temp_file_.fd;
}

void CapturedStderr::init() {
std::string CapturedStdFd::str() {
  std::string result;
  CHECK_EQ(0, TEMP_FAILURE_RETRY(lseek(fd(), 0, SEEK_SET)));
  android::base::ReadFdToString(fd(), &result);
  return result;
}

void CapturedStdFd::Init() {
#if defined(_WIN32)
  // On Windows, stderr is often buffered, so make sure it is unbuffered so
  // that we can immediately read back what was written to stderr.
  CHECK_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
  if (std_fd_ == STDERR_FILENO) CHECK_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
#endif
  old_stderr_ = dup(STDERR_FILENO);
  CHECK_NE(-1, old_stderr_);
  CHECK_NE(-1, dup2(fd(), STDERR_FILENO));
  old_fd_ = dup(std_fd_);
  CHECK_NE(-1, old_fd_);
  CHECK_NE(-1, dup2(fd(), std_fd_));
}

void CapturedStderr::reset() {
  CHECK_NE(-1, dup2(old_stderr_, STDERR_FILENO));
  CHECK_EQ(0, close(old_stderr_));
void CapturedStdFd::Reset() {
  CHECK_NE(-1, dup2(old_fd_, std_fd_));
  CHECK_EQ(0, close(old_fd_));
  // Note: cannot restore prior setvbuf() setting.
}
Loading