2 * Copyright 2004-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <folly/experimental/logging/FileHandlerFactory.h>
18 #include <folly/Exception.h>
19 #include <folly/experimental/TestUtil.h>
20 #include <folly/experimental/logging/AsyncFileWriter.h>
21 #include <folly/experimental/logging/GlogStyleFormatter.h>
22 #include <folly/experimental/logging/ImmediateFileWriter.h>
23 #include <folly/experimental/logging/StandardLogHandler.h>
24 #include <folly/portability/GTest.h>
26 using namespace folly;
27 using folly::test::TemporaryFile;
30 void checkAsyncWriter(
31 const LogWriter* writer,
32 const char* expectedPath,
33 size_t expectedMaxBufferSize) {
34 auto asyncWriter = dynamic_cast<const AsyncFileWriter*>(writer);
35 ASSERT_TRUE(asyncWriter)
36 << "FileHandlerFactory should have created an AsyncFileWriter";
37 EXPECT_EQ(expectedMaxBufferSize, asyncWriter->getMaxBufferSize());
39 // Make sure this refers to the expected output file
40 struct stat expectedStatInfo;
41 checkUnixError(stat(expectedPath, &expectedStatInfo), "stat failed");
42 struct stat actualStatInfo;
44 fstat(asyncWriter->getFile().fd(), &actualStatInfo), "fstat failed");
45 EXPECT_EQ(expectedStatInfo.st_dev, actualStatInfo.st_dev);
46 EXPECT_EQ(expectedStatInfo.st_ino, actualStatInfo.st_ino);
49 void checkAsyncWriter(
50 const LogWriter* writer,
52 size_t expectedMaxBufferSize) {
53 auto asyncWriter = dynamic_cast<const AsyncFileWriter*>(writer);
54 ASSERT_TRUE(asyncWriter)
55 << "FileHandlerFactory should have created an AsyncFileWriter";
56 EXPECT_EQ(expectedMaxBufferSize, asyncWriter->getMaxBufferSize());
57 EXPECT_EQ(expectedFD, asyncWriter->getFile().fd());
60 TEST(FileHandlerFactory, pathOnly) {
61 FileHandlerFactory factory;
63 TemporaryFile tmpFile{"logging_test"};
64 auto options = FileHandlerFactory::Options{
65 make_pair("path", tmpFile.path().string()),
67 auto handler = factory.createHandler(options);
69 auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
70 ASSERT_TRUE(stdHandler);
73 std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
74 EXPECT_TRUE(formatter)
75 << "FileHandlerFactory should have created a GlogStyleFormatter";
78 stdHandler->getWriter().get(),
79 tmpFile.path().string().c_str(),
80 AsyncFileWriter::kDefaultMaxBufferSize);
83 TEST(FileHandlerFactory, stderrStream) {
84 FileHandlerFactory factory;
86 TemporaryFile tmpFile{"logging_test"};
87 auto options = FileHandlerFactory::Options{
88 make_pair("stream", "stderr"),
90 auto handler = factory.createHandler(options);
92 auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
93 ASSERT_TRUE(stdHandler);
96 std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
97 EXPECT_TRUE(formatter)
98 << "FileHandlerFactory should have created a GlogStyleFormatter";
101 stdHandler->getWriter().get(),
103 AsyncFileWriter::kDefaultMaxBufferSize);
106 TEST(FileHandlerFactory, stdoutWithMaxBuffer) {
107 FileHandlerFactory factory;
109 TemporaryFile tmpFile{"logging_test"};
110 auto options = FileHandlerFactory::Options{
111 make_pair("stream", "stdout"),
112 make_pair("max_buffer_size", "4096"),
114 auto handler = factory.createHandler(options);
116 auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
117 ASSERT_TRUE(stdHandler);
120 std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
121 EXPECT_TRUE(formatter)
122 << "FileHandlerFactory should have created a GlogStyleFormatter";
124 checkAsyncWriter(stdHandler->getWriter().get(), STDOUT_FILENO, 4096);
127 TEST(FileHandlerFactory, pathWithMaxBufferSize) {
128 FileHandlerFactory factory;
130 TemporaryFile tmpFile{"logging_test"};
131 auto options = FileHandlerFactory::Options{
132 make_pair("path", tmpFile.path().string()),
133 make_pair("max_buffer_size", "4096000"),
135 auto handler = factory.createHandler(options);
137 auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
138 ASSERT_TRUE(stdHandler);
141 std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
142 EXPECT_TRUE(formatter)
143 << "FileHandlerFactory should have created a GlogStyleFormatter";
146 stdHandler->getWriter().get(), tmpFile.path().string().c_str(), 4096000);
149 TEST(FileHandlerFactory, nonAsyncStderr) {
150 FileHandlerFactory factory;
152 TemporaryFile tmpFile{"logging_test"};
153 auto options = FileHandlerFactory::Options{
154 make_pair("stream", "stderr"),
155 make_pair("async", "no"),
157 auto handler = factory.createHandler(options);
159 auto stdHandler = std::dynamic_pointer_cast<StandardLogHandler>(handler);
160 ASSERT_TRUE(stdHandler);
163 std::dynamic_pointer_cast<GlogStyleFormatter>(stdHandler->getFormatter());
164 EXPECT_TRUE(formatter)
165 << "FileHandlerFactory should have created a GlogStyleFormatter";
168 std::dynamic_pointer_cast<ImmediateFileWriter>(stdHandler->getWriter());
170 EXPECT_EQ(STDERR_FILENO, writer->getFile().fd());
173 TEST(FileHandlerFactory, errors) {
174 FileHandlerFactory factory;
175 TemporaryFile tmpFile{"logging_test"};
178 auto options = FileHandlerFactory::Options{};
179 EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
180 << "one of path or stream required";
184 auto options = FileHandlerFactory::Options{
185 make_pair("path", tmpFile.path().string()),
186 make_pair("stream", "stderr"),
188 EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
189 << "path and stream cannot both be specified";
193 auto options = FileHandlerFactory::Options{
194 make_pair("stream", "nonstdout"),
196 EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
201 auto options = FileHandlerFactory::Options{
202 make_pair("stream", "stderr"),
203 make_pair("async", "foobar"),
205 EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
206 << "invalid async value";
210 auto options = FileHandlerFactory::Options{
211 make_pair("stream", "stderr"),
212 make_pair("async", "false"),
213 make_pair("max_buffer_size", "1234"),
215 EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
216 << "max_buffer_size only valid for async writers";
220 auto options = FileHandlerFactory::Options{
221 make_pair("stream", "stderr"),
222 make_pair("max_buffer_size", "hello"),
224 EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
225 << "max_buffer_size must be an integer";
229 auto options = FileHandlerFactory::Options{
230 make_pair("stream", "stderr"),
231 make_pair("max_buffer_size", "0"),
233 EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
234 << "max_buffer_size must be a positive integer";
238 auto options = FileHandlerFactory::Options{
239 make_pair("stream", "stderr"),
240 make_pair("foo", "bar"),
242 EXPECT_THROW(factory.createHandler(options), std::invalid_argument)
243 << "unknown parameter foo";