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