Adds writer test case for RCU
[folly.git] / folly / experimental / logging / test / LogCategoryTest.cpp
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/Conv.h>
17 #include <folly/experimental/logging/LogCategory.h>
18 #include <folly/experimental/logging/Logger.h>
19 #include <folly/experimental/logging/LoggerDB.h>
20 #include <folly/experimental/logging/test/TestLogHandler.h>
21 #include <folly/portability/GTest.h>
22
23 using namespace folly;
24 using std::make_shared;
25 using std::shared_ptr;
26 using std::string;
27
28 TEST(LogCategory, effectiveLevel) {
29   LoggerDB db{LoggerDB::TESTING};
30   Logger foo{&db, "foo"};
31   Logger foo2{&db, "..foo.."};
32   EXPECT_EQ(foo.getCategory(), foo2.getCategory());
33
34   EXPECT_EQ(LogLevel::ERR, db.getCategory("")->getLevel());
35   EXPECT_EQ(LogLevel::ERR, db.getCategory("")->getEffectiveLevel());
36
37   EXPECT_EQ(LogLevel::MAX_LEVEL, db.getCategory("foo.bar")->getLevel());
38   EXPECT_EQ(LogLevel::ERR, db.getCategory("foo.bar")->getEffectiveLevel());
39
40   db.setLevel(".foo", LogLevel::WARN);
41   EXPECT_EQ(LogLevel::MAX_LEVEL, db.getCategory("foo.bar")->getLevel());
42   EXPECT_EQ(LogLevel::WARN, db.getCategory("foo.bar")->getEffectiveLevel());
43
44   db.setLevel(".", LogLevel::DBG0);
45   EXPECT_EQ(LogLevel::MAX_LEVEL, db.getCategory("foo.bar")->getLevel());
46   EXPECT_EQ(LogLevel::DBG0, db.getCategory("foo.bar")->getEffectiveLevel());
47
48   // Test a newly created category under .foo
49   EXPECT_EQ(LogLevel::MAX_LEVEL, db.getCategory("foo.test.1234")->getLevel());
50   EXPECT_EQ(
51       LogLevel::DBG0, db.getCategory("foo.test.1234")->getEffectiveLevel());
52
53   // Test a category that does not inherit its parent's log level
54   auto noinherit = db.getCategory("foo.test.noinherit");
55   EXPECT_EQ(LogLevel::MAX_LEVEL, noinherit->getLevel());
56   EXPECT_EQ(LogLevel::DBG0, noinherit->getEffectiveLevel());
57   noinherit->setLevel(LogLevel::CRITICAL, false);
58   EXPECT_EQ(LogLevel::CRITICAL, noinherit->getEffectiveLevel());
59
60   // Modify the root logger's level
61   db.setLevel(".", LogLevel::ERR);
62   EXPECT_EQ(LogLevel::MAX_LEVEL, db.getCategory("foo.test.1234")->getLevel());
63   EXPECT_EQ(
64       LogLevel::WARN, db.getCategory("foo.test.1234")->getEffectiveLevel());
65   EXPECT_EQ(LogLevel::MAX_LEVEL, db.getCategory("foo.test")->getLevel());
66   EXPECT_EQ(LogLevel::WARN, db.getCategory("foo.test")->getEffectiveLevel());
67   EXPECT_EQ(LogLevel::WARN, db.getCategory("foo")->getLevel());
68   EXPECT_EQ(LogLevel::WARN, db.getCategory("foo")->getEffectiveLevel());
69   EXPECT_EQ(
70       LogLevel::CRITICAL, db.getCategory("foo.test.noinherit")->getLevel());
71   EXPECT_EQ(
72       LogLevel::CRITICAL,
73       db.getCategory("foo.test.noinherit")->getEffectiveLevel());
74
75   EXPECT_EQ(LogLevel::MAX_LEVEL, db.getCategory("bar.foo.test")->getLevel());
76   EXPECT_EQ(LogLevel::ERR, db.getCategory("bar.foo.test")->getEffectiveLevel());
77 }
78
79 void testNumHandlers(size_t numHandlers) {
80   SCOPED_TRACE(folly::to<string>("num_handlers= ", numHandlers));
81   LoggerDB db{LoggerDB::TESTING};
82   db.setLevel("", LogLevel::DBG);
83
84   // Create the requested number of handlers for the foo.bar category
85   Logger foobar{&db, "foo.bar"};
86   std::vector<shared_ptr<TestLogHandler>> handlers;
87   for (size_t n = 0; n < numHandlers; ++n) {
88     handlers.emplace_back(make_shared<TestLogHandler>());
89     foobar.getCategory()->addHandler(handlers.back());
90   }
91
92   // Add a handler to the root category, to confirm that messages are
93   // propagated up to the root correctly.
94   auto rootHandler = make_shared<TestLogHandler>();
95   auto rootCategory = db.getCategory("");
96   rootCategory->addHandler(rootHandler);
97
98   // Log a message to a child of the foobar category
99   Logger childLogger{&db, "foo.bar.child"};
100   FB_LOG(childLogger, WARN, "beware");
101
102   // Make sure the message showed up at all of the handlers
103   for (const auto& handler : handlers) {
104     auto& messages = handler->getMessages();
105     ASSERT_EQ(1, messages.size());
106     EXPECT_EQ("beware", messages[0].first.getMessage());
107     EXPECT_EQ(LogLevel::WARN, messages[0].first.getLevel());
108     EXPECT_EQ(childLogger.getCategory(), messages[0].first.getCategory());
109     EXPECT_EQ(foobar.getCategory(), messages[0].second);
110   }
111   {
112     auto& messages = rootHandler->getMessages();
113     ASSERT_EQ(1, messages.size());
114     EXPECT_EQ("beware", messages[0].first.getMessage());
115     EXPECT_EQ(LogLevel::WARN, messages[0].first.getLevel());
116     EXPECT_EQ(childLogger.getCategory(), messages[0].first.getCategory());
117     EXPECT_EQ(rootCategory, messages[0].second);
118   }
119
120   // Now log a message directly to foobar
121   FB_LOG(foobar, DBG1, "just testing");
122   for (const auto& handler : handlers) {
123     auto& messages = handler->getMessages();
124     ASSERT_EQ(2, messages.size());
125     EXPECT_EQ("just testing", messages[1].first.getMessage());
126     EXPECT_EQ(LogLevel::DBG1, messages[1].first.getLevel());
127     EXPECT_EQ(foobar.getCategory(), messages[1].first.getCategory());
128     EXPECT_EQ(foobar.getCategory(), messages[1].second);
129   }
130   {
131     auto& messages = rootHandler->getMessages();
132     ASSERT_EQ(2, messages.size());
133     EXPECT_EQ("just testing", messages[1].first.getMessage());
134     EXPECT_EQ(LogLevel::DBG1, messages[1].first.getLevel());
135     EXPECT_EQ(foobar.getCategory(), messages[1].first.getCategory());
136     EXPECT_EQ(rootCategory, messages[1].second);
137   }
138
139   // Log a message to a sibling of foobar
140   Logger siblingLogger{&db, "foo.sibling"};
141   FB_LOG(siblingLogger, ERR, "oh noes");
142   for (const auto& handler : handlers) {
143     auto& messages = handler->getMessages();
144     EXPECT_EQ(2, messages.size());
145   }
146   {
147     auto& messages = rootHandler->getMessages();
148     ASSERT_EQ(3, messages.size());
149     EXPECT_EQ("oh noes", messages[2].first.getMessage());
150     EXPECT_EQ(LogLevel::ERR, messages[2].first.getLevel());
151     EXPECT_EQ(siblingLogger.getCategory(), messages[2].first.getCategory());
152     EXPECT_EQ(rootCategory, messages[2].second);
153   }
154 }
155
156 TEST(LogCategory, numHandlers) {
157   // The LogCategory code behaves differently when there are 5 or fewer
158   // LogHandlers attached to a category vs when ther are more.
159   //
160   // Test with fewer than 5 handlers.
161   testNumHandlers(1);
162   testNumHandlers(2);
163
164   // Test with exactly 5 handlers, as well as one fewer and one more, just
165   // to make sure we catch any corner cases.
166   testNumHandlers(4);
167   testNumHandlers(5);
168   testNumHandlers(6);
169
170   // Test with significantly more than 5 handlers.
171   testNumHandlers(15);
172 }