proxygen
XlogTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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/logging/xlog.h>
17 
21 #include <folly/logging/LoggerDB.h>
28 #include <folly/test/TestUtils.h>
29 #include <chrono>
30 #include <thread>
31 
32 using namespace folly;
33 using std::make_shared;
36 using namespace std::chrono_literals;
37 
38 XLOG_SET_CATEGORY_NAME("xlog_test.main_file")
39 
40 namespace {
41 class XlogTest : public testing::Test {
42  public:
43  XlogTest() {
44  // Note that the XLOG* macros always use the main LoggerDB singleton.
45  // There is no way to get them to use a test LoggerDB during unit tests.
46  //
47  // In order to ensure that changes to the LoggerDB singleton do not persist
48  // across test functions we reset the configuration to a fixed state before
49  // each test starts.
50  auto config =
51  parseLogConfig(".=WARN:default; default=stream:stream=stderr");
53  }
54 };
55 } // namespace
56 
57 TEST_F(XlogTest, xlogName) {
58  EXPECT_EQ("xlog_test.main_file", XLOG_GET_CATEGORY_NAME());
59  EXPECT_EQ("xlog_test.main_file", XLOG_GET_CATEGORY()->getName());
60 }
61 
62 TEST_F(XlogTest, xlogIf) {
63  auto handler = make_shared<TestLogHandler>();
65  auto& messages = handler->getMessages();
66 
67  // info messages are not enabled initially.
70  XLOG_IF(INFO, false, "testing 1");
71  EXPECT_EQ(0, messages.size());
72  messages.clear();
73 
74  XLOG_IF(INFO, true, "testing 1");
75  EXPECT_EQ(0, messages.size());
76  messages.clear();
77 
78  // Increase the log level, then log a message.
79  LoggerDB::get().setLevel("xlog_test.main_file", LogLevel::DBG1);
80  XLOG_IF(DBG1, false, "testing: ", 1, 2, 3);
81  ASSERT_EQ(0, messages.size());
82  messages.clear();
83 
84  XLOG_IF(DBG1, true, "testing: ", 1, 2, 3);
85  ASSERT_EQ(1, messages.size());
86  messages.clear();
87 
88  // more complex conditional expressions
89  std::array<bool, 2> conds = {{false, true}};
90  for (unsigned i = 0; i < conds.size(); i++) {
91  for (unsigned j = 0; j < conds.size(); j++) {
92  XLOG_IF(DBG1, conds[i] && conds[j], "testing conditional");
93  EXPECT_EQ((conds[i] && conds[j]) ? 1 : 0, messages.size());
94  messages.clear();
95 
96  XLOG_IF(DBG1, conds[i] || conds[j], "testing conditional");
97  EXPECT_EQ((conds[i] || conds[j]) ? 1 : 0, messages.size());
98  messages.clear();
99  }
100  }
101 
102  XLOG_IF(DBG1, 0x6 & 0x2, "More conditional 1");
103  EXPECT_EQ(1, messages.size());
104  messages.clear();
105 
106  XLOG_IF(DBG1, 0x6 | 0x2, "More conditional 2");
107  EXPECT_EQ(1, messages.size());
108  messages.clear();
109 
110  XLOG_IF(DBG1, 0x6 | 0x2 ? true : false, "More conditional 3");
111  EXPECT_EQ(1, messages.size());
112  messages.clear();
113 
114  XLOG_IF(DBG1, 0x6 | 0x2 ? true : false, "More conditional 3");
115  EXPECT_EQ(1, messages.size());
116  messages.clear();
117 
118  XLOG_IF(DBG1, 0x3 & 0x4 ? true : false, "More conditional 4");
119  EXPECT_EQ(0, messages.size());
120  messages.clear();
121 
122  XLOG_IF(DBG1, false ? true : false, "More conditional 5");
123  EXPECT_EQ(0, messages.size());
124  messages.clear();
125 
126  XLOGF_IF(DBG1, false, "number: {:>3d}; string: {}", 12, "foo");
127  ASSERT_EQ(0, messages.size());
128  messages.clear();
129  XLOGF_IF(DBG1, true, "number: {:>3d}; string: {}", 12, "foo");
130  ASSERT_EQ(1, messages.size());
131  messages.clear();
132 }
133 
134 TEST_F(XlogTest, xlog) {
135  auto handler = make_shared<TestLogHandler>();
136  LoggerDB::get().getCategory("xlog_test")->addHandler(handler);
137  auto& messages = handler->getMessages();
138 
139  // info messages are not enabled initially.
142  XLOG(INFO, "testing 1");
143  EXPECT_EQ(0, messages.size());
144  messages.clear();
145 
146  // Increase the log level, then log a message.
147  LoggerDB::get().setLevel("xlog_test.main_file", LogLevel::DBG1);
148 
149  XLOG(DBG1, "testing: ", 1, 2, 3);
150  ASSERT_EQ(1, messages.size());
151  EXPECT_EQ("testing: 123", messages[0].first.getMessage());
152  EXPECT_TRUE(messages[0].first.getFileName().endsWith("XlogTest.cpp"))
153  << "unexpected file name: " << messages[0].first.getFileName();
154  EXPECT_EQ(LogLevel::DBG1, messages[0].first.getLevel());
155  EXPECT_EQ("xlog_test.main_file", messages[0].first.getCategory()->getName());
156  EXPECT_EQ("xlog_test", messages[0].second->getName());
157  messages.clear();
158 
159  XLOGF(WARN, "number: {:>3d}; string: {}", 12, "foo");
160  ASSERT_EQ(1, messages.size());
161  EXPECT_EQ("number: 12; string: foo", messages[0].first.getMessage());
162  EXPECT_TRUE(messages[0].first.getFileName().endsWith("XlogTest.cpp"))
163  << "unexpected file name: " << messages[0].first.getFileName();
164  EXPECT_EQ(LogLevel::WARN, messages[0].first.getLevel());
165  EXPECT_EQ("xlog_test.main_file", messages[0].first.getCategory()->getName());
166  EXPECT_EQ("xlog_test", messages[0].second->getName());
167  messages.clear();
168 
169  XLOG(DBG2, "this log check should not pass");
170  EXPECT_EQ(0, messages.size());
171  messages.clear();
172 
173  // Test stream arguments to XLOG()
174  XLOG(INFO) << "stream test: " << 1 << ", two, " << 3;
175  ASSERT_EQ(1, messages.size());
176  EXPECT_EQ("stream test: 1, two, 3", messages[0].first.getMessage());
177  EXPECT_TRUE(messages[0].first.getFileName().endsWith("XlogTest.cpp"))
178  << "unexpected file name: " << messages[0].first.getFileName();
179  EXPECT_EQ(LogLevel::INFO, messages[0].first.getLevel());
180  EXPECT_EQ("xlog_test.main_file", messages[0].first.getCategory()->getName());
181  EXPECT_EQ("xlog_test", messages[0].second->getName());
182  messages.clear();
183 }
184 
185 TEST_F(XlogTest, perFileCategoryHandling) {
186  using namespace logging_test;
187 
188  auto handler = make_shared<TestLogHandler>();
189  LoggerDB::get().getCategory("folly.logging.test")->addHandler(handler);
190  LoggerDB::get().setLevel("folly.logging.test", LogLevel::DBG9);
191  auto& messages = handler->getMessages();
192 
193  // Use the simple helper function in XlogHeader2
194  testXlogHdrFunction("factor", 99);
195  ASSERT_EQ(1, messages.size());
196  EXPECT_EQ("test: factor=99", messages[0].first.getMessage());
197  EXPECT_TRUE(messages[0].first.getFileName().endsWith("XlogHeader2.h"))
198  << "unexpected file name: " << messages[0].first.getFileName();
199  EXPECT_EQ(LogLevel::DBG3, messages[0].first.getLevel());
200  EXPECT_EQ(
201  "folly.logging.test.XlogHeader2.h",
202  messages[0].first.getCategory()->getName());
203  EXPECT_EQ("folly.logging.test", messages[0].second->getName());
204  messages.clear();
205 
206  // Test the loop function from XlogHeader1
207  testXlogHdrLoop(3, "hello world");
208  ASSERT_EQ(5, messages.size());
209  EXPECT_EQ("starting: hello world", messages[0].first.getMessage());
210  EXPECT_TRUE(messages[0].first.getFileName().endsWith("XlogHeader1.h"))
211  << "unexpected file name: " << messages[0].first.getFileName();
212  EXPECT_EQ(LogLevel::DBG1, messages[0].first.getLevel());
213  EXPECT_EQ(
214  "folly.logging.test.XlogHeader1.h",
215  messages[0].first.getCategory()->getName());
216  EXPECT_EQ("folly.logging.test", messages[0].second->getName());
217 
218  EXPECT_EQ("test: hello world", messages[1].first.getMessage());
219  EXPECT_EQ("test: hello world", messages[2].first.getMessage());
220  EXPECT_EQ("test: hello world", messages[3].first.getMessage());
221  EXPECT_EQ("finished: hello world", messages[4].first.getMessage());
222  EXPECT_EQ(LogLevel::DBG5, messages[1].first.getLevel());
223  EXPECT_EQ(LogLevel::DBG5, messages[2].first.getLevel());
224  EXPECT_EQ(LogLevel::DBG5, messages[3].first.getLevel());
225  EXPECT_EQ(LogLevel::DBG1, messages[4].first.getLevel());
226  messages.clear();
227 
228  // Reduce the log level so that the messages inside the loop
229  // should not be logged.
230  LoggerDB::get().setLevel("folly.logging.test", LogLevel::DBG2);
231  testXlogHdrLoop(300, "hello world");
232  ASSERT_EQ(2, messages.size());
233  EXPECT_EQ("starting: hello world", messages[0].first.getMessage());
234  EXPECT_EQ("finished: hello world", messages[1].first.getMessage());
235  messages.clear();
236 
237  // Call the helpers function in XlogFile1.cpp and XlogFile2.cpp and makes
238  // sure their categories are reported correctly.
239  testXlogFile1Dbg1("foobar 1234");
240  ASSERT_EQ(1, messages.size());
241  EXPECT_EQ("file1: foobar 1234", messages[0].first.getMessage());
242  EXPECT_EQ(
243  "folly.logging.test.XlogFile1.cpp",
244  messages[0].first.getCategory()->getName());
245  messages.clear();
246 
247  testXlogFile2Dbg1("hello world");
248  ASSERT_EQ(1, messages.size());
249  EXPECT_EQ("file2: hello world", messages[0].first.getMessage());
250  EXPECT_EQ(
251  "folly.logging.test.XlogFile2.cpp",
252  messages[0].first.getCategory()->getName());
253  messages.clear();
254 
255  // Adjust the log level and make sure the changes take effect for the .cpp
256  // file categories
257  LoggerDB::get().setLevel("folly.logging.test", LogLevel::INFO);
258  testXlogFile1Dbg1("log check should fail now");
259  testXlogFile2Dbg1("this should fail too");
260  EXPECT_EQ(0, messages.size());
261  messages.clear();
262 
263  LoggerDB::get().setLevel("folly.logging.test.XlogFile1", LogLevel::DBG1);
264  testXlogFile1Dbg1("this log check should pass now");
265  testXlogFile2Dbg1("but this one should still fail");
266  ASSERT_EQ(1, messages.size());
267  EXPECT_EQ(
268  "file1: this log check should pass now", messages[0].first.getMessage());
269  EXPECT_EQ(
270  "folly.logging.test.XlogFile1.cpp",
271  messages[0].first.getCategory()->getName());
272  messages.clear();
273 }
274 
275 TEST_F(XlogTest, rateLimiting) {
276  auto handler = make_shared<TestLogHandler>();
277  LoggerDB::get().getCategory("xlog_test")->addHandler(handler);
278  LoggerDB::get().setLevel("xlog_test", LogLevel::DBG1);
279 
280  // Test XLOG_EVERY_N
281  for (size_t n = 0; n < 50; ++n) {
282  XLOG_EVERY_N(DBG1, 7, "msg ", n);
283  }
284  EXPECT_THAT(
285  handler->getMessageValues(),
286  ElementsAre(
287  "msg 0",
288  "msg 7",
289  "msg 14",
290  "msg 21",
291  "msg 28",
292  "msg 35",
293  "msg 42",
294  "msg 49"));
295  handler->clearMessages();
296 
297  // Test XLOG_EVERY_MS and XLOG_N_PER_MS
298  // We test these together to minimize the number of sleep operations.
299  for (size_t n = 0; n < 10; ++n) {
300  // Integer arguments are treated as millisecond
301  XLOG_EVERY_MS(DBG1, 100, "int arg ", n);
302  // Other duration arguments also work, as long as they are
303  // coarser than milliseconds
304  XLOG_EVERY_MS(DBG1, 100ms, "ms arg ", n);
305  XLOG_EVERY_MS(DBG1, 1s, "s arg ", n);
306 
307  // Use XLOG_N_PER_MS() too
308  XLOG_N_PER_MS(DBG1, 2, 100, "2x int arg ", n);
309  XLOG_N_PER_MS(DBG1, 1, 100ms, "1x ms arg ", n);
310  XLOG_N_PER_MS(DBG1, 3, 1s, "3x s arg ", n);
311 
312  // Sleep for 100ms between iterations 5 and 6
313  if (n == 5) {
314  /* sleep override */ std::this_thread::sleep_for(110ms);
315  }
316  }
317  EXPECT_THAT(
318  handler->getMessageValues(),
320  "int arg 0",
321  "ms arg 0",
322  "s arg 0",
323  "2x int arg 0",
324  "1x ms arg 0",
325  "3x s arg 0",
326  "2x int arg 1",
327  "3x s arg 1",
328  "3x s arg 2",
329  "int arg 6",
330  "ms arg 6",
331  "2x int arg 6",
332  "1x ms arg 6",
333  "2x int arg 7",
334  }));
335  handler->clearMessages();
336 }
337 
338 TEST_F(XlogTest, getXlogCategoryName) {
339  EXPECT_EQ("foo.cpp", getXlogCategoryNameForFile("foo.cpp"));
340  EXPECT_EQ("foo.h", getXlogCategoryNameForFile("foo.h"));
341 
342  // Directory separators should be translated to "." during LogName
343  // canonicalization
344  EXPECT_EQ("src/test/foo.cpp", getXlogCategoryNameForFile("src/test/foo.cpp"));
345  EXPECT_EQ(
346  "src.test.foo.cpp",
348  EXPECT_EQ("src/test/foo.h", getXlogCategoryNameForFile("src/test/foo.h"));
349  EXPECT_EQ(
350  "src.test.foo.h",
352 
353  // Buck's directory prefixes for generated source files
354  // should be stripped out
355  EXPECT_EQ(
356  "myproject.generated_header.h",
358  "buck-out/gen/myproject#headers/myproject/generated_header.h")));
359  EXPECT_EQ(
360  "foo.bar.test.h",
362  "buck-out/gen/foo/bar#header-map,headers/foo/bar/test.h")));
363 }
364 
366  EXPECT_STREQ("c/d.txt", xlogStripFilename("/a/b/c/d.txt", "/a/b"));
367  EXPECT_STREQ("c/d.txt", xlogStripFilename("/a/b/c/d.txt", "/a/b/"));
368  EXPECT_STREQ(
369  "ships/cruiser.cpp",
371  "/home/johndoe/src/spacesim/ships/cruiser.cpp",
372  "/home/johndoe/src/spacesim"));
373  EXPECT_STREQ(
374  "ships/cruiser.cpp",
375  xlogStripFilename("src/spacesim/ships/cruiser.cpp", "src/spacesim"));
376 
377  // Test with multiple prefixes
378  EXPECT_STREQ("c/d.txt", xlogStripFilename("/a/b/c/d.txt", "/x/y:1/2:/a/b"));
379  EXPECT_STREQ("c/d.txt", xlogStripFilename("/a/b/c/d.txt", "/x/y:/a/b:/1/2"));
380 
381  EXPECT_STREQ(
382  "/foobar/src/test.cpp", xlogStripFilename("/foobar/src/test.cpp", "/foo"))
383  << "should only strip full directory name matches";
384  EXPECT_STREQ(
385  "src/test.cpp",
386  xlogStripFilename("/foobar/src/test.cpp", "/foo:/foobar"));
387 
388  EXPECT_STREQ(
389  "/a/b/c/d.txt", xlogStripFilename("/a/b/c/d.txt", "/a/b/c/d.txt"))
390  << "should not strip if the result will be empty";
391  EXPECT_STREQ("c/d.txt", xlogStripFilename("/a/b/c/d.txt", ":/x/y::/a/b:"))
392  << "empty prefixes in the prefix list should be ignored";
393 
394  EXPECT_STREQ("d.txt", xlogStripFilename("/a/b/c/d.txt", "/a/b/c:/a"))
395  << "only the first prefix match should be honored";
396  EXPECT_STREQ("b/c/d.txt", xlogStripFilename("/a/b/c/d.txt", "/a:/a/b/c"))
397  << "only the first prefix match should be honored";
398 
399  // xlogStripFilename() should ideally be a purely compile-time evaluation.
400  // Use a static_assert() to ensure that it can be evaluated at compile time.
401  // We use EXPECT_STREQ() checks above for most of the testing since it
402  // produces nicer messages on failure.
403  static_assert(
405  xlogStripFilename("/my/project/src/test.cpp", "/my/project"),
406  "src/test.cpp") == 0,
407  "incorrect xlogStripFilename() behavior");
408 }
#define XLOG_SET_CATEGORY_NAME(category)
Definition: xlog.h:310
static struct message messages[5]
Definition: test.c:75
void testXlogFile2Dbg1(folly::StringPiece msg)
Definition: XlogFile2.cpp:20
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
#define XLOG_EVERY_N(level, n,...)
Definition: xlog.h:121
LogCategory * getCategory(folly::StringPiece name)
Definition: LoggerDB.cpp:133
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
void testXlogHdrFunction(folly::StringPiece str, int value)
Definition: XlogHeader2.h:22
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
LogConfig parseLogConfig(StringPiece value)
void resetConfig(const LogConfig &config)
Definition: LoggerDB.cpp:435
void testXlogFile1Dbg1(folly::StringPiece msg)
Definition: XlogFile1.cpp:20
AHArrayT::Config config
void handler(int, siginfo_t *, void *)
#define EXPECT_STREQ(s1, s2)
Definition: gtest.h:1995
StringPiece getXlogCategoryNameForFile(StringPiece filename)
Definition: xlog.cpp:57
constexpr const char * xlogStripFilename(const char *filename, const char *prefixes)
Definition: xlog.h:575
internal::ElementsAreArrayMatcher< typename::std::iterator_traits< Iter >::value_type > ElementsAreArray(Iter first, Iter last)
static std::string canonicalize(folly::StringPiece name)
Definition: LogName.cpp:26
#define XLOG_GET_CATEGORY_NAME()
Definition: xlog.h:273
#define XLOG_IF(level, cond,...)
Definition: xlog.h:68
void testXlogHdrLoop(size_t numIters, folly::StringPiece arg)
Definition: XlogHeader1.h:24
constexpr int constexpr_strcmp(const Char *s1, const Char *s2)
Definition: Constexpr.h:75
#define XLOGF_IF(level, cond, fmt, arg1,...)
Definition: xlog.h:90
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define EXPECT_THAT(value, matcher)
#define XLOG_EVERY_MS(level, ms,...)
Definition: xlog.h:105
#define XLOG_GET_CATEGORY()
Definition: xlog.h:286
void setLevel(folly::StringPiece name, LogLevel level, bool inherit=true)
Definition: LoggerDB.cpp:147
static set< string > s
#define XLOGF(level, fmt, arg1,...)
Definition: xlog.h:77
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
#define XLOG(level,...)
Definition: xlog.h:57
void addHandler(std::shared_ptr< LogHandler > handler)
#define XLOG_IS_ON(level)
Definition: xlog.h:241
internal::ElementsAreMatcher< ::testing::tuple<> > ElementsAre()
TEST(SequencedExecutor, CPUThreadPoolExecutor)
#define XLOG_N_PER_MS(level, count, ms,...)
Definition: xlog.h:138
constexpr detail::First first
Definition: Base-inl.h:2553
static LoggerDB & get()
Definition: LoggerDB.cpp:112