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