1 /* 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef RTC_BASE_FILE_ROTATING_STREAM_H_ 12 #define RTC_BASE_FILE_ROTATING_STREAM_H_ 13 14 #include <stddef.h> 15 16 #include <memory> 17 #include <string> 18 #include <vector> 19 20 #include "rtc_base/constructor_magic.h" 21 #include "rtc_base/stream.h" 22 #include "rtc_base/system/file_wrapper.h" 23 24 namespace rtc { 25 26 // FileRotatingStream writes to a file in the directory specified in the 27 // constructor. It rotates the files once the current file is full. The 28 // individual file size and the number of files used is configurable in the 29 // constructor. Open() must be called before using this stream. 30 class FileRotatingStream : public StreamInterface { 31 public: 32 // Use this constructor for reading a directory previously written to with 33 // this stream. 34 FileRotatingStream(const std::string& dir_path, 35 const std::string& file_prefix); 36 37 // Use this constructor for writing to a directory. Files in the directory 38 // matching the prefix will be deleted on open. 39 FileRotatingStream(const std::string& dir_path, 40 const std::string& file_prefix, 41 size_t max_file_size, 42 size_t num_files); 43 44 ~FileRotatingStream() override; 45 46 // StreamInterface methods. 47 StreamState GetState() const override; 48 StreamResult Read(void* buffer, 49 size_t buffer_len, 50 size_t* read, 51 int* error) override; 52 StreamResult Write(const void* data, 53 size_t data_len, 54 size_t* written, 55 int* error) override; 56 bool Flush() override; 57 void Close() override; 58 59 // Opens the appropriate file(s). Call this before using the stream. 60 bool Open(); 61 62 // Disabling buffering causes writes to block until disk is updated. This is 63 // enabled by default for performance. 64 bool DisableBuffering(); 65 66 // Returns the path used for the i-th newest file, where the 0th file is the 67 // newest file. The file may or may not exist, this is just used for 68 // formatting. Index must be less than GetNumFiles(). 69 std::string GetFilePath(size_t index) const; 70 71 // Returns the number of files that will used by this stream. GetNumFiles()72 size_t GetNumFiles() const { return file_names_.size(); } 73 74 protected: GetMaxFileSize()75 size_t GetMaxFileSize() const { return max_file_size_; } 76 SetMaxFileSize(size_t size)77 void SetMaxFileSize(size_t size) { max_file_size_ = size; } 78 GetRotationIndex()79 size_t GetRotationIndex() const { return rotation_index_; } 80 SetRotationIndex(size_t index)81 void SetRotationIndex(size_t index) { rotation_index_ = index; } 82 OnRotation()83 virtual void OnRotation() {} 84 85 private: 86 bool OpenCurrentFile(); 87 void CloseCurrentFile(); 88 89 // Rotates the files by creating a new current file, renaming the 90 // existing files, and deleting the oldest one. e.g. 91 // file_0 -> file_1 92 // file_1 -> file_2 93 // file_2 -> delete 94 // create new file_0 95 void RotateFiles(); 96 97 // Private version of GetFilePath. 98 std::string GetFilePath(size_t index, size_t num_files) const; 99 100 const std::string dir_path_; 101 const std::string file_prefix_; 102 103 // File we're currently writing to. 104 webrtc::FileWrapper file_; 105 // Convenience storage for file names so we don't generate them over and over. 106 std::vector<std::string> file_names_; 107 size_t max_file_size_; 108 size_t current_file_index_; 109 // The rotation index indicates the index of the file that will be 110 // deleted first on rotation. Indices lower than this index will be rotated. 111 size_t rotation_index_; 112 // Number of bytes written to current file. We need this because with 113 // buffering the file size read from disk might not be accurate. 114 size_t current_bytes_written_; 115 bool disable_buffering_; 116 117 RTC_DISALLOW_COPY_AND_ASSIGN(FileRotatingStream); 118 }; 119 120 // CallSessionFileRotatingStream is meant to be used in situations where we will 121 // have limited disk space. Its purpose is to write logs up to a 122 // maximum size. Once the maximum size is exceeded, logs from the middle are 123 // deleted whereas logs from the beginning and end are preserved. The reason for 124 // this is because we anticipate that in WebRTC the beginning and end of the 125 // logs are most useful for call diagnostics. 126 // 127 // This implementation simply writes to a single file until 128 // |max_total_log_size| / 2 bytes are written to it, and subsequently writes to 129 // a set of rotating files. We do this by inheriting FileRotatingStream and 130 // setting the appropriate internal variables so that we don't delete the last 131 // (earliest) file on rotate, and that that file's size is bigger. 132 // 133 // Open() must be called before using this stream. 134 135 // To read the logs produced by this class, one can use the companion class 136 // CallSessionFileRotatingStreamReader. 137 class CallSessionFileRotatingStream : public FileRotatingStream { 138 public: 139 // Use this constructor for writing to a directory. Files in the directory 140 // matching what's used by the stream will be deleted. |max_total_log_size| 141 // must be at least 4. 142 CallSessionFileRotatingStream(const std::string& dir_path, 143 size_t max_total_log_size); ~CallSessionFileRotatingStream()144 ~CallSessionFileRotatingStream() override {} 145 146 protected: 147 void OnRotation() override; 148 149 private: 150 static size_t GetRotatingLogSize(size_t max_total_log_size); 151 static size_t GetNumRotatingLogFiles(size_t max_total_log_size); 152 static const size_t kRotatingLogFileDefaultSize; 153 154 const size_t max_total_log_size_; 155 size_t num_rotations_; 156 157 RTC_DISALLOW_COPY_AND_ASSIGN(CallSessionFileRotatingStream); 158 }; 159 160 // This is a convenience class, to read all files produced by a 161 // FileRotatingStream, all in one go. Typical use calls GetSize and ReadData 162 // only once. The list of file names to read is based on the contents of the log 163 // directory at construction time. 164 class FileRotatingStreamReader { 165 public: 166 FileRotatingStreamReader(const std::string& dir_path, 167 const std::string& file_prefix); 168 ~FileRotatingStreamReader(); 169 size_t GetSize() const; 170 size_t ReadAll(void* buffer, size_t size) const; 171 172 private: 173 std::vector<std::string> file_names_; 174 }; 175 176 class CallSessionFileRotatingStreamReader : public FileRotatingStreamReader { 177 public: 178 CallSessionFileRotatingStreamReader(const std::string& dir_path); 179 }; 180 181 } // namespace rtc 182 183 #endif // RTC_BASE_FILE_ROTATING_STREAM_H_ 184