93dc13a4d1db504cd92c1da7ddf20496731f165a
[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 <set>
19
20 #include <folly/Conv.h>
21 #include <folly/MapUtil.h>
22 #include <folly/experimental/logging/AsyncFileWriter.h>
23 #include <folly/experimental/logging/GlogStyleFormatter.h>
24 #include <folly/experimental/logging/ImmediateFileWriter.h>
25 #include <folly/experimental/logging/StandardLogHandler.h>
26
27 using std::make_shared;
28 using std::shared_ptr;
29 using std::string;
30
31 namespace folly {
32
33 std::shared_ptr<LogHandler> FileHandlerFactory::createHandler(
34     const Options& options) {
35   // Raise an error if we receive unexpected options
36   auto knownOptions =
37       std::set<std::string>{"path", "stream", "async", "max_buffer_size"};
38   for (const auto& entry : options) {
39     if (knownOptions.find(entry.first) == knownOptions.end()) {
40       throw std::invalid_argument(to<string>(
41           "unknown parameter \"", entry.first, "\" for FileHandlerFactory"));
42     }
43   }
44
45   // Construct the formatter
46   // TODO: We should eventually support parameters to control the formatter
47   // behavior.
48   auto formatter = make_shared<GlogStyleFormatter>();
49
50   // Get the output file to use
51   File outputFile;
52   auto* path = get_ptr(options, "path");
53   auto* stream = get_ptr(options, "stream");
54   if (path && stream) {
55     throw std::invalid_argument(
56         "cannot specify both \"path\" and \"stream\" "
57         "parameters for FileHandlerFactory");
58   } else if (path) {
59     outputFile = File{*path, O_WRONLY | O_APPEND | O_CREAT};
60   } else if (stream) {
61     if (*stream == "stderr") {
62       outputFile = File{STDERR_FILENO, /* ownsFd */ false};
63     } else if (*stream == "stdout") {
64       outputFile = File{STDOUT_FILENO, /* ownsFd */ false};
65     } else {
66       throw std::invalid_argument(to<string>(
67           "unknown stream for FileHandlerFactory: \"",
68           *stream,
69           "\" expected one of stdout or stderr"));
70     }
71   } else {
72     throw std::invalid_argument(
73         "must specify a \"path\" or \"stream\" "
74         "parameter for FileHandlerFactory");
75   }
76
77   // Determine whether we should use ImmediateFileWriter or AsyncFileWriter
78   shared_ptr<LogWriter> writer;
79   bool async = true;
80   auto* asyncOption = get_ptr(options, "async");
81   if (asyncOption) {
82     try {
83       async = to<bool>(*asyncOption);
84     } catch (const std::exception& ex) {
85       throw std::invalid_argument(to<string>(
86           "expected a boolean value for FileHandlerFactory \"async\" "
87           "parameter: ",
88           *asyncOption));
89     }
90   }
91   auto* maxBufferOption = get_ptr(options, "max_buffer_size");
92   if (async) {
93     auto asyncWriter = make_shared<AsyncFileWriter>(std::move(outputFile));
94     if (maxBufferOption) {
95       size_t maxBufferSize;
96       try {
97         maxBufferSize = to<size_t>(*maxBufferOption);
98       } catch (const std::exception& ex) {
99         throw std::invalid_argument(to<string>(
100             "expected an integer value for FileHandlerFactory "
101             "\"max_buffer_size\": ",
102             *maxBufferOption));
103       }
104       if (maxBufferSize == 0) {
105         throw std::invalid_argument(to<string>(
106             "expected a positive value for FileHandlerFactory "
107             "\"max_buffer_size\": ",
108             *maxBufferOption));
109       }
110       asyncWriter->setMaxBufferSize(maxBufferSize);
111     }
112     writer = std::move(asyncWriter);
113   } else {
114     if (maxBufferOption) {
115       throw std::invalid_argument(to<string>(
116           "the \"max_buffer_size\" option is only valid for async file "
117           "handlers"));
118     }
119     writer = make_shared<ImmediateFileWriter>(std::move(outputFile));
120   }
121
122   return make_shared<StandardLogHandler>(
123       LogHandlerConfig{getType(), options}, formatter, writer);
124 }
125
126 } // namespace folly