logging.h提供的功能
这篇博客我们来分析logging.h提供的功能,引⽤这个⽂件可以#include <android-ba/logging.h>,⽽这个⽂件在logging.cpp中实现。⾸先我们来看下其注释:提供了⼀个c++ stream的接⼝,⽽且PLOG会打印出具体的错误,还⽀持logcat,stderr,dmesg的打印。
//
// Google-style C++ logging.
//
// This header provides a C++ stream interface to logging.
//
// To log:
//
// LOG(INFO) << "Some text; " << some_value;
//
// Replace `INFO` with any verity from `enum LogSeverity`.
//
// To log the result of a failed function and include the string
// reprentation of `errno` at the end:
//
// PLOG(ERROR) << "Write failed";
//
// The output will be something like `Write failed: I/O error`.
// Remember this as 'P' as in perror(3).
//
/
/ To output your own types, simply implement operator<< as normal.
//
// By default, output goes to logcat on Android and stderr on the host.
// A process can u `SetLogger` to decide where all logging goes.
// Implementations are provided for logcat, stderr, and dmesg.
// This header also provides asrtions:
//
// CHECK(must_be_true);
// CHECK_EQ(a, b) << z_is_interesting_too;
// NOTE: For Windows, you must include logging.h after windows.h to allow the
// following code to suppress the evil ERROR macro:
我们来看下这个头⽂件,使⽤之前必须先调⽤InitLogging函数,这⾥有三个Logger可供选择,KernelLogger、StderrLogger、LogdLogger,⽽在android系统下默认是LogdLogger。
void KernelLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*); void StderrLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
void DefaultAborter(const char* abort_message);
#ifdef __ANDROID__
// We expo this even though it is the default becau a ur that wants to
// override the default log buffer will have to construct this themlves.
class LogdLogger {
public:
explicit LogdLogger(LogId default_log_id = android::ba::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 bad on ANDROID_LOG_TAGS environment variable.
// We need to par a string that looks like
//
// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
//
// 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 ud to reveal or conceal logs with specific tags.
#ifdef __ANDROID__非主流个性签名
#define INIT_LOGGING_DEFAULT_LOGGER LogdLogger()
#el
#define INIT_LOGGING_DEFAULT_LOGGER StderrLogger
#endif
void InitLogging(char* argv[],
LogFunction&& logger = INIT_LOGGING_DEFAULT_LOGGER,
AbortFunction&& aborter = DefaultAborter);
#undef INIT_LOGGING_DEFAULT_LOGGER
下⾯我们再来看下这三个Logger的实现。
kernel的就是往dev/kmsg中write
void KernelLogger(android::ba::LogId, android::ba::LogSeverity verity,
const char* tag, const char*, unsigned int, const char* msg) {
// clang-format off
static constexpr int kLogSeverityToKernelLogLevel[] = {
[android::ba::VERBOSE] = 7, // KERN_DEBUG (there is no verbo kernel log
// level)
[android::ba::DEBUG] = 7, // KERN_DEBUG
[android::ba::INFO] = 6, // KERN_INFO
[android::ba::WARNING] = 4, // KERN_WARNING
[android::ba::ERROR] = 3, // KERN_ERROR
[android::ba::FATAL_WITHOUT_ABORT] = 2, // KERN_CRIT
[android::ba::FATAL] = 2, // KERN_CRIT
};
有关军训的作文
// clang-format on
static_asrt(arraysize(kLogSeverityToKernelLogLevel) == android::ba::FATAL + 1,
"Mismatch in size of kLogSeverityToKernelLogLevel and values in LogSeverity");
static int klog_fd = TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC)); if (klog_fd == -1) return;
int level = kLogSeverityToKernelLogLevel[verity];
// The kernel's printk buffer is only 1024 bytes.
// TODO: should we automatically break up long lines into multiple lines?
// Or we could log but with something like "..." at the end?
象神寓意char buf[1024];
size_t size = snprintf(buf, sizeof(buf), "<%d>%s: %s\n", level, tag, msg);
if (size > sizeof(buf)) {
size = snprintf(buf, sizeof(buf), "<%d>%s: %zu-byte message too long for printk\n",
level, tag, size);
}
iovec iov[1];
iov[0].iov_ba = buf;
iov[0].iov_len = size;
TEMP_FAILURE_RETRY(writev(klog_fd, iov, 1));
}
下⾯就是stderr
void StderrLogger(LogId, LogSeverity verity, const char*, const char* file,
unsigned int line, const char* message) {
struct tm now;
time_t t = time(nullptr);
#if defined(_WIN32)
localtime_s(&now, &t);
#el
localtime_r(&t, &now);
#endif
char timestamp[32];
北京野钓strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
static const char log_characters[] = "VDIWEFF";
static_asrt(arraysize(log_characters) - 1 == FATAL + 1,
"Mismatch in size of log_characters and values in LogSeverity");
柏油便
char verity_char = log_characters[verity];
fprintf(stderr, "%s %c %s %5d %5d %s:%u] %s\n", ProgramInvocationName().c_str(),
verity_char, timestamp, getpid(), GetThreadId(), file, line, message);
}
logd就是最后调⽤__android_log_buf_print函数往logd中写。这个函数是调⽤了log/log.h的
void LogdLogger::operator()(LogId id, LogSeverity verity, const char* tag,
const char* file, unsigned int line,
const char* message) {
static constexpr android_LogPriority kLogSeverityToAndroidLogPriority[] = {
ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
ANDROID_LOG_FATAL,
};
未来的交通static_asrt(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
"Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity");
int priority = kLogSeverityToAndroidLogPriority[verity];
if (id == DEFAULT) {
id = default_log_id_;
}
static constexpr log_id kLogIdToAndroidLogId[] = {
LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
};
static_asrt(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
"Mismatch in size of kLogIdToAndroidLogId and values in LogId");
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);
新鲜橄榄怎么吃
} el {
__android_log_buf_print(lg_id, priority, tag, "%s", message);
}
这个⽂件提供了很⽅便的功能,不⽌可以使⽤c++的流,⽽且可以各种log切换,只要在InitLogging指定不⼀样的logger就可以了。
我们来看init的⼀个例⼦,init在⼀开始的时候就调⽤了InitKernelLogging函数,这个函数把标准输⼊输出,标准错误全部写
到/sys/fs/linux/null,也就没有了。然后定了⼀InitLogging为kernelLogger,就是写在ksmg中。
void InitKernelLogging(char* argv[]) {
// Make stdin/stdout/stderr all point to /dev/null.
int fd = open("/sys/fs/linux/null", O_RDWR);
if (fd == -1) {
int saved_errno = errno;
android::ba::InitLogging(argv, &android::ba::KernelLogger);
errno = saved_errno;
PLOG(FATAL) << "Couldn't open /sys/fs/linux/null";
}
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
if (fd > 2) clo(fd);
android::ba::InitLogging(argv, &android::ba::KernelLogger);
}