blob: 69dc177fc532069cca1ea812a7ea56e82f4b3247 [file] [log] [blame]
// 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