| Index: chrome/browser/chromeos/system_logs/single_log_source.cc
|
| diff --git a/chrome/browser/chromeos/system_logs/single_log_source.cc b/chrome/browser/chromeos/system_logs/single_log_source.cc
|
| deleted file mode 100644
|
| index 005cb4ac59c12150d6986995ef4f39c707a97be2..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/chromeos/system_logs/single_log_source.cc
|
| +++ /dev/null
|
| @@ -1,251 +0,0 @@
|
| -// Copyright 2017 The Chromium 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 "chrome/browser/chromeos/system_logs/single_log_source.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/files/file_path.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/process/process_info.h"
|
| -#include "base/strings/string_split.h"
|
| -#include "base/task_scheduler/post_task.h"
|
| -#include "base/time/time.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -
|
| -namespace system_logs {
|
| -
|
| -namespace {
|
| -
|
| -constexpr char kDefaultSystemLogDirPath[] = "/var/log";
|
| -constexpr int kMaxNumAllowedLogRotationsDuringFileRead = 3;
|
| -
|
| -// For log files that contain old logging, start reading from the first
|
| -// timestamp that is less than this amount of time before the current session of
|
| -// Chrome started.
|
| -constexpr base::TimeDelta kLogCutoffTimeBeforeChromeStart =
|
| - base::TimeDelta::FromMinutes(10);
|
| -
|
| -// A custom timestamp for when the current Chrome session started. Used during
|
| -// testing to override the actual time.
|
| -const base::Time* g_chrome_start_time_for_test = nullptr;
|
| -
|
| -// Converts a logs source type to the corresponding file path, relative to the
|
| -// base system log directory path. In the future, if non-file source types are
|
| -// added, this function should return an empty file path.
|
| -base::FilePath GetLogFileSourceRelativeFilePath(
|
| - SingleLogSource::SupportedSource source) {
|
| - switch (source) {
|
| - case SingleLogSource::SupportedSource::kMessages:
|
| - return base::FilePath("messages");
|
| - case SingleLogSource::SupportedSource::kUiLatest:
|
| - return base::FilePath("ui/ui.LATEST");
|
| - case SingleLogSource::SupportedSource::kAtrusLog:
|
| - return base::FilePath("atrus.log");
|
| - }
|
| - NOTREACHED();
|
| - return base::FilePath();
|
| -}
|
| -
|
| -// Returns the inode value of file at |path|, or 0 if it doesn't exist or is
|
| -// otherwise unable to be accessed for file system info.
|
| -ino_t GetInodeValue(const base::FilePath& path) {
|
| - struct stat file_stats;
|
| - if (stat(path.value().c_str(), &file_stats) != 0)
|
| - return 0;
|
| - return file_stats.st_ino;
|
| -}
|
| -
|
| -// Attempts to store a string |value| in |*response| under |key|. If there is
|
| -// already a string in |*response| under |key|, appends |value| to the existing
|
| -// string value.
|
| -void AppendToSystemLogsResponse(SystemLogsResponse* response,
|
| - const std::string& key,
|
| - const std::string& value) {
|
| - auto iter = response->find(key);
|
| - if (iter == response->end())
|
| - response->emplace(key, value);
|
| - else
|
| - iter->second += value;
|
| -}
|
| -
|
| -// Returns the time that the current Chrome process started. Will instead return
|
| -// |*g_chrome_start_time_for_test| if it is set.
|
| -base::Time GetChromeStartTime() {
|
| - if (g_chrome_start_time_for_test)
|
| - return *g_chrome_start_time_for_test;
|
| - return base::CurrentProcessInfo::CreationTime();
|
| -}
|
| -
|
| -// Returns the file offset into |path| of the first line that starts with a
|
| -// timestamp no earlier than |time|. Returns 0 if no such offset could be
|
| -// determined (e.g. can't open file, no timestamps present).
|
| -size_t GetFirstFileOffsetWithTime(const base::FilePath& path,
|
| - const base::Time& time) {
|
| - base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
| - if (!file.IsValid())
|
| - return 0;
|
| -
|
| - const size_t file_size = file.GetLength();
|
| - if (file_size == 0)
|
| - return 0;
|
| -
|
| - std::string file_contents;
|
| - file_contents.resize(file_size);
|
| - size_t size_read = file.ReadAtCurrentPos(&file_contents[0], file_size);
|
| -
|
| - if (size_read < file_size)
|
| - return 0;
|
| -
|
| - std::vector<base::StringPiece> lines = base::SplitStringPiece(
|
| - file_contents, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
|
| -
|
| - bool any_timestamp_found = false;
|
| -
|
| - // Find the first line with timestamp >= |time|. If a line has no timestamp,
|
| - // just advance to the next line.
|
| - size_t offset = 0;
|
| - base::Time timestamp;
|
| - for (const auto& line : lines) {
|
| - if (base::Time::FromString(line.as_string().c_str(), ×tamp)) {
|
| - any_timestamp_found = true;
|
| -
|
| - if (timestamp >= time)
|
| - break;
|
| - }
|
| -
|
| - // Include the newline in the offset.
|
| - offset += line.length() + 1;
|
| - }
|
| -
|
| - // If the file does not have any timestamps at all, don't skip any contents.
|
| - if (!any_timestamp_found)
|
| - return 0;
|
| -
|
| - if (offset > 0 && offset >= file_size && lines.back().as_string().empty()) {
|
| - // The last line may or may not have ended with a newline. If it ended with
|
| - // a newline, |lines| would end with an extra empty line after the newline.
|
| - // This would have resulted in an extra nonexistent newline being counted
|
| - // during the computation of |offset|.
|
| - --offset;
|
| - }
|
| - return offset;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -SingleLogSource::SingleLogSource(SupportedSource source_type)
|
| - : SystemLogsSource(GetLogFileSourceRelativeFilePath(source_type).value()),
|
| - source_type_(source_type),
|
| - log_file_dir_path_(kDefaultSystemLogDirPath),
|
| - num_bytes_read_(0),
|
| - file_inode_(0),
|
| - weak_ptr_factory_(this) {}
|
| -
|
| -SingleLogSource::~SingleLogSource() {}
|
| -
|
| -// static
|
| -void SingleLogSource::SetChromeStartTimeForTesting(
|
| - const base::Time* start_time) {
|
| - g_chrome_start_time_for_test = start_time;
|
| -}
|
| -
|
| -void SingleLogSource::Fetch(const SysLogsSourceCallback& callback) {
|
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| - DCHECK(!callback.is_null());
|
| -
|
| - SystemLogsResponse* response = new SystemLogsResponse;
|
| - base::PostTaskWithTraitsAndReply(
|
| - FROM_HERE,
|
| - base::TaskTraits(base::MayBlock(), base::TaskPriority::BACKGROUND),
|
| - base::Bind(&SingleLogSource::ReadFile, weak_ptr_factory_.GetWeakPtr(),
|
| - kMaxNumAllowedLogRotationsDuringFileRead, response),
|
| - base::Bind(callback, base::Owned(response)));
|
| -}
|
| -
|
| -base::FilePath SingleLogSource::GetLogFilePath() const {
|
| - return base::FilePath(log_file_dir_path_).Append(source_name());
|
| -}
|
| -
|
| -void SingleLogSource::ReadFile(size_t num_rotations_allowed,
|
| - SystemLogsResponse* result) {
|
| - // Attempt to open the file if it was not previously opened.
|
| - if (!file_.IsValid()) {
|
| - file_.Initialize(GetLogFilePath(),
|
| - base::File::FLAG_OPEN | base::File::FLAG_READ);
|
| - if (!file_.IsValid())
|
| - return;
|
| -
|
| - // Determine actual offset from which to start reading.
|
| - if (source_type_ == SupportedSource::kMessages) {
|
| - const base::Time earliest_log_time =
|
| - GetChromeStartTime() - kLogCutoffTimeBeforeChromeStart;
|
| -
|
| - num_bytes_read_ =
|
| - GetFirstFileOffsetWithTime(GetLogFilePath(), earliest_log_time);
|
| - } else {
|
| - num_bytes_read_ = 0;
|
| - }
|
| - file_.Seek(base::File::FROM_BEGIN, num_bytes_read_);
|
| -
|
| - file_inode_ = GetInodeValue(GetLogFilePath());
|
| - }
|
| -
|
| - // Check for file size reset.
|
| - const size_t length = file_.GetLength();
|
| - if (length < num_bytes_read_) {
|
| - num_bytes_read_ = 0;
|
| - file_.Seek(base::File::FROM_BEGIN, 0);
|
| - }
|
| -
|
| - // Read from file until end.
|
| - const size_t size_to_read = length - num_bytes_read_;
|
| - std::string result_string;
|
| - result_string.resize(size_to_read);
|
| - size_t size_read = file_.ReadAtCurrentPos(&result_string[0], size_to_read);
|
| - result_string.resize(size_read);
|
| -
|
| - const bool file_was_rotated = file_inode_ != GetInodeValue(GetLogFilePath());
|
| - const bool should_handle_file_rotation =
|
| - file_was_rotated && num_rotations_allowed > 0;
|
| -
|
| - // The reader may only read complete lines. The exception is when there is a
|
| - // rotation, in which case all the remaining contents of the old log file
|
| - // should be read before moving on to read the new log file.
|
| - if ((result_string.empty() || result_string.back() != '\n') &&
|
| - !should_handle_file_rotation) {
|
| - // If an incomplete line was read, return only the part that includes whole
|
| - // lines.
|
| - size_t last_newline_pos = result_string.find_last_of('\n');
|
| - if (last_newline_pos == std::string::npos) {
|
| - file_.Seek(base::File::FROM_CURRENT, -size_read);
|
| - AppendToSystemLogsResponse(result, source_name(), "");
|
| - return;
|
| - }
|
| - // The part of the string that will be returned includes the newline itself.
|
| - size_t adjusted_size_read = last_newline_pos + 1;
|
| - file_.Seek(base::File::FROM_CURRENT, -size_read + adjusted_size_read);
|
| - result_string.resize(adjusted_size_read);
|
| -
|
| - // Update |size_read| to reflect that the read was only up to the last
|
| - // newline.
|
| - size_read = adjusted_size_read;
|
| - }
|
| -
|
| - num_bytes_read_ += size_read;
|
| -
|
| - // Pass it back to the callback.
|
| - AppendToSystemLogsResponse(result, source_name(),
|
| - anonymizer_.Anonymize(result_string));
|
| -
|
| - // If the file was rotated, close the file handle and call this function
|
| - // again, to read from the new file.
|
| - if (should_handle_file_rotation) {
|
| - file_.Close();
|
| - num_bytes_read_ = 0;
|
| - file_inode_ = 0;
|
| - ReadFile(num_rotations_allowed - 1, result);
|
| - }
|
| -}
|
| -
|
| -} // namespace system_logs
|
|
|