logging: add a LogHandler::flush() call
[folly.git] / folly / experimental / logging / AsyncFileWriter.h
1 /*
2  * Copyright 2004-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17
18 #include <condition_variable>
19 #include <mutex>
20 #include <thread>
21
22 #include <folly/File.h>
23 #include <folly/Range.h>
24 #include <folly/Synchronized.h>
25 #include <folly/experimental/logging/LogWriter.h>
26
27 namespace folly {
28
29 /**
30  * A LogWriter implementation that asynchronously writes to a file descriptor.
31  *
32  * This class performs the log I/O in a separarate thread.
33  *
34  * The advantage of this class over ImmediateFileWriter is that logging I/O can
35  * never slow down or block your normal program operation.  If log messages are
36  * generated faster than they can be written, messages will be dropped (and an
37  * indication of how many messages were dropped will be written to the log file
38  * when we are able to catch up a bit.)
39  *
40  * However, one downside is that if your program crashes, not all log messages
41  * may have been written, so you may lose messages generated immediately before
42  * the crash.
43  */
44 class AsyncFileWriter : public LogWriter {
45  public:
46   /**
47    * Construct an AsyncFileWriter that appends to the file at the specified
48    * path.
49    */
50   explicit AsyncFileWriter(folly::StringPiece path);
51
52   /**
53    * Construct an AsyncFileWriter that writes to the specified File object.
54    */
55   explicit AsyncFileWriter(folly::File&& file);
56
57   ~AsyncFileWriter();
58
59   void writeMessage(folly::StringPiece buffer, uint32_t flags = 0) override;
60   void writeMessage(std::string&& buffer, uint32_t flags = 0) override;
61
62   /**
63    * Block until the I/O thread has finished writing all messages that
64    * were already enqueued when flush() was called.
65    */
66   void flush() override;
67
68  private:
69   /*
70    * A simple implementation using two queues.
71    * All writer threads enqueue into one queue while the I/O thread is
72    * processing the other.
73    *
74    * We could potentially also provide an implementation using folly::MPMCQueue
75    * in the future, which may improve contention under very high write loads.
76    */
77   struct Data {
78     std::array<std::vector<std::string>, 2> queues;
79     bool stop{false};
80     bool ioThreadDone{false};
81     uint64_t ioThreadCounter{0};
82     size_t maxBufferBytes{1024 * 1024};
83     size_t currentBufferSize{0};
84     size_t numDiscarded{0};
85
86     std::vector<std::string>* getCurrentQueue() {
87       return &queues[ioThreadCounter & 0x1];
88     }
89   };
90
91   void ioThread();
92   void performIO(std::vector<std::string>* ioQueue);
93
94   void onIoError(const std::exception& ex);
95   std::string getNumDiscardedMsg(size_t numDiscarded);
96
97   folly::File file_;
98   folly::Synchronized<Data, std::mutex> data_;
99   /**
100    * messageReady_ is signaled by writer threads whenever they add a new
101    * message to the current queue.
102    */
103   std::condition_variable messageReady_;
104   /**
105    * ioCV_ is signaled by the I/O thread each time it increments
106    * the ioThreadCounter (once each time around its loop).
107    */
108   std::condition_variable ioCV_;
109
110   /**
111    * The I/O thread.
112    *
113    * This should come last, since all other member variables need to be
114    * constructed before the I/O thread starts.
115    */
116   std::thread ioThread_;
117 };
118 }