Loading base/include/android-base/logging.h +9 −0 Original line number Diff line number Diff line Loading @@ -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); Loading base/include/android-base/test_utils.h +19 −7 Original line number Diff line number Diff line Loading @@ -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) \ Loading base/logging.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -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); Loading base/logging_test.cpp +22 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; } base/test_utils.cpp +23 −14 Original line number Diff line number Diff line Loading @@ -14,7 +14,6 @@ * limitations under the License. */ #include "android-base/logging.h" #include "android-base/test_utils.h" #include <fcntl.h> Loading @@ -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) { Loading Loading @@ -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
base/include/android-base/logging.h +9 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
base/include/android-base/test_utils.h +19 −7 Original line number Diff line number Diff line Loading @@ -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) \ Loading
base/logging.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
base/logging_test.cpp +22 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; }
base/test_utils.cpp +23 −14 Original line number Diff line number Diff line Loading @@ -14,7 +14,6 @@ * limitations under the License. */ #include "android-base/logging.h" #include "android-base/test_utils.h" #include <fcntl.h> Loading @@ -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) { Loading Loading @@ -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. }