add support for displaying log files on standard input
Change-Id: I5b4ec4a170fa79089d250dbda5ef4daaaa2ea742
diff --git a/aos/linux_code/logging/binary_log_file.cc b/aos/linux_code/logging/binary_log_file.cc
index 2738c16..0142db3 100644
--- a/aos/linux_code/logging/binary_log_file.cc
+++ b/aos/linux_code/logging/binary_log_file.cc
@@ -36,8 +36,8 @@
}
bool LogFileAccessor::IsLastPage() {
- if (is_last_page_ != 0) {
- return is_last_page_ == 2;
+ if (is_last_page_ != Maybe::kUnknown) {
+ return is_last_page_ == Maybe::kYes;
}
struct stat info;
@@ -45,7 +45,7 @@
PLOG(FATAL, "fstat(%d, %p) failed", fd_, &info);
}
bool r = offset_ == static_cast<off_t>(info.st_size - kPageSize);
- is_last_page_ = r ? 2 : 1;
+ is_last_page_ = r ? Maybe::kYes : Maybe::kNo;
return r;
}
@@ -55,26 +55,55 @@
PLOG(FATAL, "ftruncate(%d, %zd) failed", fd_, kPageSize);
}
}
- current_ = static_cast<char *>(
- mmap(NULL, kPageSize, PROT_READ | (writable_ ? PROT_WRITE : 0),
- MAP_SHARED, fd_, offset_));
- if (current_ == MAP_FAILED) {
- PLOG(FATAL,
- "mmap(NULL, %zd, PROT_READ [ | PROT_WRITE], MAP_SHARED, %d, %jd)"
- " failed", kPageSize, fd_, static_cast<intmax_t>(offset_));
- }
- if (madvise(current_, kPageSize, MADV_SEQUENTIAL | MADV_WILLNEED) == -1) {
- PLOG(WARNING, "madvise(%p, %zd, MADV_SEQUENTIAL | MADV_WILLNEED) failed",
- current_, kPageSize);
+
+ if (use_read_ == Maybe::kYes) {
+ ssize_t todo = kPageSize;
+ while (todo > 0) {
+ ssize_t result = read(fd_, current_ + (kPageSize - todo), todo);
+ if (result == -1) {
+ PLOG(FATAL, "read(%d, %p, %zu) failed", fd_,
+ current_ + (kPageSize - todo), todo);
+ }
+ todo -= result;
+ }
+ CHECK_EQ(0, todo);
+ } else {
+ current_ = static_cast<char *>(
+ mmap(NULL, kPageSize, PROT_READ | (writable_ ? PROT_WRITE : 0),
+ MAP_SHARED, fd_, offset_));
+ if (current_ == MAP_FAILED) {
+ if (!writable_ && use_read_ == Maybe::kUnknown && errno == ENODEV) {
+ LOG(INFO, "Falling back to reading the file using read(2).\n");
+ use_read_ = Maybe::kYes;
+ current_ = new char[kPageSize];
+ MapNextPage();
+ return;
+ } else {
+ PLOG(FATAL,
+ "mmap(NULL, %zd, PROT_READ [ | PROT_WRITE], MAP_SHARED, %d, %jd)"
+ " failed",
+ kPageSize, fd_, static_cast<intmax_t>(offset_));
+ }
+ } else {
+ use_read_ = Maybe::kNo;
+ }
+ if (madvise(current_, kPageSize, MADV_SEQUENTIAL | MADV_WILLNEED) == -1) {
+ PLOG(WARNING, "madvise(%p, %zd, MADV_SEQUENTIAL | MADV_WILLNEED) failed",
+ current_, kPageSize);
+ }
}
offset_ += kPageSize;
}
void LogFileAccessor::Unmap(void *location) {
- if (munmap(location, kPageSize) == -1) {
- PLOG(FATAL, "munmap(%p, %zd) failed", location, kPageSize);
+ CHECK_NE(Maybe::kUnknown, use_read_);
+
+ if (use_read_ == Maybe::kNo) {
+ if (munmap(location, kPageSize) == -1) {
+ PLOG(FATAL, "munmap(%p, %zd) failed", location, kPageSize);
+ }
}
- is_last_page_ = 0;
+ is_last_page_ = Maybe::kUnknown;
position_ = 0;
}
@@ -123,6 +152,8 @@
} // namespace
void LogFileReader::CheckCurrentPageReadable() {
+ if (definitely_use_read()) return;
+
if (sigsetjmp(jump_context, 1) == 0) {
struct sigaction action;
action.sa_sigaction = CheckCurrentPageReadableHandler;
diff --git a/aos/linux_code/logging/binary_log_file.h b/aos/linux_code/logging/binary_log_file.h
index 54e64d8..ea4651b 100644
--- a/aos/linux_code/logging/binary_log_file.h
+++ b/aos/linux_code/logging/binary_log_file.h
@@ -46,7 +46,7 @@
// for readers keeping up with a live writer.
//
// Gets initialized to 0 by ftruncate.
- //
+ //
// There will be something here after the last message on a "page" set to 2
// (by the futex_set) to indicate that the next message is on the next page.
mutex marker;
@@ -85,6 +85,11 @@
class LogFileAccessor {
public:
LogFileAccessor(int fd, bool writable);
+ ~LogFileAccessor() {
+ if (use_read_ == Maybe::kYes) {
+ delete[] current_;
+ }
+ }
// Asynchronously syncs all open mappings.
void Sync() const;
@@ -118,7 +123,15 @@
position_ += kAlignment - (position_ % kAlignment);
}
+ protected:
+ bool definitely_use_read() const { return use_read_ == Maybe::kYes; }
+ bool definitely_use_mmap() const { return use_read_ == Maybe::kNo; }
+
private:
+ // Used for representing things that we might know to be true/false or we
+ // might not know (yet).
+ enum class Maybe { kUnknown, kYes, kNo };
+
const int fd_;
const bool writable_;
@@ -127,8 +140,10 @@
char *current_;
size_t position_;
- // 0 = unknown, 1 = no, 2 = yes
- int is_last_page_ = 0;
+ Maybe is_last_page_ = Maybe::kUnknown;
+
+ // Use read instead of mmap (necessary for fds that don't support mmap).
+ Maybe use_read_ = Maybe::kUnknown;
};
class LogFileReader : public LogFileAccessor {
diff --git a/aos/linux_code/logging/log_displayer.cc b/aos/linux_code/logging/log_displayer.cc
index bc00ddc..05a12fe 100644
--- a/aos/linux_code/logging/log_displayer.cc
+++ b/aos/linux_code/logging/log_displayer.cc
@@ -23,6 +23,7 @@
const char *kArgsHelp = "[OPTION]... [FILE]\n"
"Display log file FILE (created by BinaryLogReader) to stdout.\n"
"FILE is \"aos_log-current\" by default.\n"
+ "FILE can also be \"-\" to read from standard input.\n"
"\n"
" -n, --name NAME only display entries from processes named NAME\n"
" -l, --level LEVEL "
@@ -215,7 +216,12 @@
fprintf(stderr, "displaying down to level %s from file '%s'\n",
::aos::logging::log_str(filter_level), filename);
- int fd = open(filename, O_RDONLY);
+ int fd;
+ if (strcmp(filename, "-") == 0) {
+ fd = STDIN_FILENO;
+ } else {
+ fd = open(filename, O_RDONLY);
+ }
if (fd == -1) {
PLOG(FATAL, "couldn't open file '%s' for reading", filename);