| // Copyright 2020 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "croslog/log_entry_reader.h" |
| |
| #include <list> |
| #include <utility> |
| |
| #include "base/optional.h" |
| #include "base/strings/string_util.h" |
| |
| #include "croslog/log_parser_syslog.h" |
| |
| namespace croslog { |
| |
| LogEntryReader::LogEntryReader(base::FilePath log_file, |
| std::unique_ptr<LogParser> parser_in, |
| bool install_change_watcher) |
| : file_path_(log_file), |
| line_reader_(install_change_watcher ? LogLineReader::Backend::FILE_FOLLOW |
| : LogLineReader::Backend::FILE), |
| parser_(std::move(parser_in)) { |
| line_reader_.OpenFile(std::move(log_file)); |
| } |
| |
| MaybeLogEntry LogEntryReader::GetPreviousEntry() { |
| // If we have looked ahead, go back to the current position and invalidate the |
| // cache. |
| if (next_entry_.has_value()) { |
| line_reader_.Backward(); |
| next_entry_.reset(); |
| } |
| |
| std::list<std::string> lines; |
| // Reads preceding lines until a parsable line, which should be the first |
| // line of log entry, comes. |
| while (true) { |
| base::Optional<std::string> line = line_reader_.Backward(); |
| if (!line.has_value()) { |
| // No more entry |
| return base::nullopt; |
| } |
| |
| MaybeLogEntry entry = parser_->Parse(std::move(*line)); |
| if (entry.has_value()) { |
| if (!lines.empty()) |
| entry->AppendLinesToMessage(lines); |
| return entry; |
| } |
| lines.push_front(*line); |
| } |
| } |
| |
| MaybeLogEntry LogEntryReader::GetNextEntry() { |
| MaybeLogEntry entry; |
| if (!next_entry_.has_value()) { |
| // Reads a next lines with skipping non-parsable lines. |
| while (true) { |
| base::Optional<std::string> line = line_reader_.Forward(); |
| if (!line.has_value()) { |
| // No more entry |
| return base::nullopt; |
| } |
| |
| MaybeLogEntry maybe_entry = parser_->Parse(std::move(*line)); |
| if (!maybe_entry.has_value()) { |
| // Parse failed. Go to the next line. |
| continue; |
| } |
| |
| entry.emplace(std::move(*maybe_entry)); |
| break; |
| } |
| } else { |
| entry.emplace(std::move(*next_entry_)); |
| next_entry_.reset(); |
| } |
| |
| std::list<std::string> lines; |
| // Reads succeeding lines until a parsable line, which should be the first |
| // line of the next log entry, comes. |
| while (true) { |
| base::Optional<std::string> line = line_reader_.Forward(); |
| if (!line.has_value()) { |
| // No more entry |
| break; |
| } |
| |
| MaybeLogEntry maybe_entry = parser_->Parse(std::move(*line)); |
| if (maybe_entry.has_value()) { |
| next_entry_.emplace(std::move(*maybe_entry)); |
| break; |
| } |
| |
| lines.push_back(std::move(*line)); |
| } |
| |
| entry->AppendLinesToMessage(lines); |
| return entry; |
| } |
| |
| void LogEntryReader::SetPositionLast() { |
| line_reader_.SetPositionLast(); |
| } |
| |
| void LogEntryReader::AddObserver(LogLineReader::Observer* obs) { |
| line_reader_.AddObserver(obs); |
| } |
| |
| void LogEntryReader::RemoveObserver(LogLineReader::Observer* obs) { |
| line_reader_.RemoveObserver(obs); |
| } |
| |
| } // namespace croslog |