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.
20 #include <folly/Conv.h>
21 #include <folly/Exception.h>
22 #include <folly/FileUtil.h>
23 #include <folly/experimental/TestUtil.h>
24 #include <folly/experimental/logging/ImmediateFileWriter.h>
25 #include <folly/experimental/logging/LoggerDB.h>
26 #include <folly/portability/GMock.h>
27 #include <folly/portability/GTest.h>
29 using namespace folly;
30 using folly::test::TemporaryFile;
32 TEST(ImmediateFileWriter, readBatch) {
33 TemporaryFile tmpFile{"logging_test"};
34 ImmediateFileWriter writer{folly::File{tmpFile.fd(), false}};
36 // Write several messages
37 for (int n = 0; n < 10; ++n) {
38 writer.writeMessage(folly::to<std::string>("message ", n, "\n"));
41 // Read the log file and confirm it contains all of the expected messages
43 auto ret = folly::readFile(tmpFile.path().native().c_str(), data);
46 std::string expected =
57 EXPECT_EQ(expected, data);
60 TEST(ImmediateFileWriter, immediateRead) {
61 TemporaryFile tmpFile{"logging_test"};
62 ImmediateFileWriter writer{tmpFile.path().native()};
64 // Write several messages, and read each one back immediately
66 folly::File readf{tmpFile.path().native()};
67 for (int n = 0; n < 10; ++n) {
68 writer.writeMessage(folly::to<std::string>("message ", n, "\n"));
70 std::array<char, 1024> buf;
71 auto sizeRead = folly::readFull(readf.fd(), buf.data(), buf.size());
72 ASSERT_GT(sizeRead, 0);
74 folly::to<std::string>("message ", n, "\n"),
75 StringPiece(buf.data(), sizeRead));
81 static std::vector<std::string>* internalWarnings;
83 void handleLoggingError(
84 StringPiece /* file */,
87 internalWarnings->emplace_back(std::move(msg));
91 TEST(ImmediateFileWriter, ioError) {
92 std::array<int, 2> fds;
93 auto rc = pipe(fds.data());
94 folly::checkUnixError(rc, "failed to create pipe");
95 signal(SIGPIPE, SIG_IGN);
97 // Set the LoggerDB internal warning handler so we can record the messages
98 std::vector<std::string> logErrors;
99 internalWarnings = &logErrors;
100 LoggerDB::setInternalWarningHandler(handleLoggingError);
102 // Create an ImmediateFileWriter that refers to a pipe whose read end is
103 // closed, then log a bunch of messages to it.
106 size_t numMessages = 100;
108 ImmediateFileWriter writer{folly::File{fds[1], true}};
109 for (size_t n = 0; n < numMessages; ++n) {
110 writer.writeMessage(folly::to<std::string>("message ", n, "\n"));
115 LoggerDB::setInternalWarningHandler(nullptr);
117 // ImmediateFileWriter should have generated one warning
118 // for each attempt to log a message.
120 // (The default internalWarning() handler would have rate limited these
121 // messages, but our test handler does not perform rate limiting.)
122 for (const auto& msg : logErrors) {
123 EXPECT_THAT(msg, testing::HasSubstr("error writing to log file"));
124 EXPECT_THAT(msg, testing::HasSubstr("Broken pipe"));
126 EXPECT_EQ(numMessages, logErrors.size());