c398654f6a5f5a1df16f2ca8e94843558d9a51d4
[folly.git] / folly / experimental / logging / FileHandlerFactory.cpp
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 #include <folly/experimental/logging/FileHandlerFactory.h>
17
18 #include <folly/Conv.h>
19 #include <folly/experimental/logging/AsyncFileWriter.h>
20 #include <folly/experimental/logging/ImmediateFileWriter.h>
21 #include <folly/experimental/logging/StandardLogHandler.h>
22 #include <folly/experimental/logging/StandardLogHandlerFactory.h>
23
24 using std::make_shared;
25 using std::shared_ptr;
26 using std::string;
27
28 namespace folly {
29
30 class FileHandlerFactory::WriterFactory
31     : public StandardLogHandlerFactory::WriterFactory {
32  public:
33   bool processOption(StringPiece name, StringPiece value) override {
34     if (name == "path") {
35       if (!stream_.empty()) {
36         throw std::invalid_argument(
37             "cannot specify both \"path\" and \"stream\" "
38             "parameters for FileHandlerFactory");
39       }
40       path_ = value.str();
41       return true;
42     } else if (name == "stream") {
43       if (!path_.empty()) {
44         throw std::invalid_argument(
45             "cannot specify both \"path\" and \"stream\" "
46             "parameters for FileHandlerFactory");
47       }
48       stream_ = value.str();
49       return true;
50     } else if (name == "async") {
51       async_ = to<bool>(value);
52       return true;
53     } else if (name == "max_buffer_size") {
54       auto size = to<size_t>(value);
55       if (size == 0) {
56         throw std::invalid_argument(to<string>("must be a postive number"));
57       }
58       maxBufferSize_ = size;
59       return true;
60     } else {
61       return false;
62     }
63   }
64
65   std::shared_ptr<LogWriter> createWriter() override {
66     // Get the output file to use
67     File outputFile;
68     if (!path_.empty()) {
69       outputFile = File{path_, O_WRONLY | O_APPEND | O_CREAT};
70     } else if (stream_ == "stderr") {
71       outputFile = File{STDERR_FILENO, /* ownsFd */ false};
72     } else if (stream_ == "stdout") {
73       outputFile = File{STDOUT_FILENO, /* ownsFd */ false};
74     } else {
75       throw std::invalid_argument(to<string>(
76           "unknown stream for FileHandlerFactory: \"",
77           stream_,
78           "\" expected one of stdout or stderr"));
79     }
80
81     // Determine whether we should use ImmediateFileWriter or AsyncFileWriter
82     if (async_) {
83       auto asyncWriter = make_shared<AsyncFileWriter>(std::move(outputFile));
84       if (maxBufferSize_.hasValue()) {
85         asyncWriter->setMaxBufferSize(maxBufferSize_.value());
86       }
87       return asyncWriter;
88     } else {
89       if (maxBufferSize_.hasValue()) {
90         throw std::invalid_argument(to<string>(
91             "the \"max_buffer_size\" option is only valid for async file "
92             "handlers"));
93       }
94       return make_shared<ImmediateFileWriter>(std::move(outputFile));
95     }
96   }
97
98   std::string path_;
99   std::string stream_;
100   bool async_{true};
101   Optional<size_t> maxBufferSize_;
102 };
103
104 std::shared_ptr<LogHandler> FileHandlerFactory::createHandler(
105     const Options& options) {
106   WriterFactory writerFactory;
107   return StandardLogHandlerFactory::createHandler(
108       getType(), &writerFactory, options);
109 }
110
111 } // namespace folly