| // 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. |
| |
| #ifndef CROSLOG_LOG_LINE_READER_H_ |
| #define CROSLOG_LOG_LINE_READER_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/files/memory_mapped_file.h" |
| #include "base/observer_list.h" |
| #include "base/observer_list_types.h" |
| |
| #include "croslog/file_change_watcher.h" |
| #include "croslog/file_map_reader.h" |
| #include "croslog/log_entry.h" |
| #include "croslog/log_parser.h" |
| |
| namespace croslog { |
| |
| /* |
| * This class is responsible for |
| * - Reading logs line by line from the file |
| * - Automatically switching the file when the file is rotated. |
| */ |
| class LogLineReader : public FileChangeWatcher::Observer { |
| public: |
| class Observer : public base::CheckedObserver { |
| public: |
| virtual void OnFileChanged(LogLineReader* reader) = 0; |
| }; |
| |
| enum class Backend { |
| FILE, |
| FILE_FOLLOW, |
| MEMORY_FOR_TEST, |
| }; |
| |
| // Sets the maximum limit of length of line. |
| static void SetMaxLineLengthForTest(int64_t max_line_length); |
| |
| explicit LogLineReader(Backend backend_mode); |
| LogLineReader(const LogLineReader&) = delete; |
| LogLineReader& operator=(const LogLineReader&) = delete; |
| |
| virtual ~LogLineReader(); |
| |
| // Open the file to read. |
| void OpenFile(const base::FilePath& file_path); |
| // Open the buffer on memory instead of a file. |
| void OpenMemoryBufferForTest(const char* buffer, size_t size); |
| |
| // Read the next line from log. |
| base::Optional<std::string> Forward(); |
| // Read the previous line from log. |
| base::Optional<std::string> Backward(); |
| |
| // Set the position to read last. |
| void SetPositionLast(); |
| // Add a observer to retrieve file change events. |
| void AddObserver(Observer* obs); |
| // Remove a observer to retrieve file change events. |
| void RemoveObserver(Observer* obs); |
| |
| // Retrieve the current position in bytes. |
| off_t position() const { return pos_; } |
| |
| // Returns the file path of the target. |
| const base::FilePath& file_path() const { return file_path_; } |
| |
| private: |
| void ReloadRotatedFile(); |
| void OnFileContentMaybeChanged() override; |
| void OnFileNameMaybeChanged() override; |
| |
| std::string GetString(std::unique_ptr<FileMapReader::MappedBuffer> buffer, |
| uint64_t offset, |
| uint64_t length) const; |
| |
| // Information about the target file. These field are initialized by |
| // OpenFile() for either FILE or FILE_FOLLOW. |
| base::File file_; |
| base::FilePath file_path_; |
| ino_t file_inode_ = 0; |
| std::unique_ptr<base::MemoryMappedFile> mmap_; |
| |
| // This is initialized by OpenFile() for FILE_FOLLOW backend. |
| FileChangeWatcher* file_change_watcher_ = nullptr; |
| |
| std::unique_ptr<FileMapReader> reader_; |
| const Backend backend_mode_; |
| bool rotated_ = false; |
| |
| // Position of the current read. |
| // - Usually be at the first character of line. But it's not when the line is |
| // is too long to read or the file content is unexpectedly changed by |
| // another process. |
| // - Must be in the interval of [0, reader_->GetFileSize()]. |
| // (|buffer->GetChar(pos)| is invalid if |pos| == |reader_->GetFileSize()|) |
| int64_t pos_ = 0; |
| |
| base::ObserverList<Observer> observers_; |
| }; |
| |
| } // namespace croslog |
| |
| #endif // CROSLOG_LOG_LINE_READER_H_ |