1 #include <gtest/gtest.h>
4 #include "common/Clock.h"
5 #include "include/coredumpctl.h"
6 #include "SubsystemMap.h"
8 #include "global/global_init.h"
9 #include "common/ceph_argparse.h"
10 #include "global/global_context.h"
11 #include "common/dout.h"
14 using namespace ceph::logging
;
19 subs
.set_log_level(0, 10);
20 subs
.set_gather_level(0, 10);
22 subs
.set_log_level(1, 20);
23 subs
.set_gather_level(1, 1);
25 subs
.set_log_level(2, 20);
26 subs
.set_gather_level(2, 2);
28 subs
.set_log_level(3, 10);
29 subs
.set_gather_level(3, 3);
34 log
.set_log_file("foo");
35 log
.reopen_log_file();
37 log
.set_stderr_level(5, -1);
40 for (int i
=0; i
<100; i
++) {
43 if (subs
.should_gather(sys
, l
)) {
44 MutableEntry
e(l
, sys
);
45 log
.submit_entry(std::move(e
));
59 subs
.set_log_level(1, 1);
60 subs
.set_gather_level(1, 1);
63 log
.set_log_file("foo");
64 log
.reopen_log_file();
69 auto& out
= e
.get_ostream();
70 out
<< (std::streambuf
*)nullptr;
71 EXPECT_TRUE(out
.bad()); // writing nullptr to a stream sets its badbit
72 log
.submit_entry(std::move(e
));
76 auto& out
= e
.get_ostream();
77 EXPECT_FALSE(out
.bad()); // should not see failures from previous log entry
79 log
.submit_entry(std::move(e
));
88 TEST(Log
, ManyNoGather
)
91 subs
.set_log_level(1, 1);
92 subs
.set_gather_level(1, 1);
95 log
.set_log_file("big");
96 log
.reopen_log_file();
97 for (int i
=0; i
<many
; i
++) {
99 if (subs
.should_gather(1, l
))
100 log
.submit_entry(MutableEntry(1, 0));
107 TEST(Log
, ManyGatherLog
)
110 subs
.set_log_level(1, 20);
111 subs
.set_gather_level(1, 10);
114 log
.set_log_file("big");
115 log
.reopen_log_file();
116 for (int i
=0; i
<many
; i
++) {
118 if (subs
.should_gather(1, l
)) {
119 MutableEntry
e(l
, 1);
120 e
.get_ostream() << "this is a long string asdf asdf asdf asdf asdf asdf asd fasd fasdf ";
121 log
.submit_entry(std::move(e
));
128 TEST(Log
, ManyGatherLogStackSpillover
)
131 subs
.set_log_level(1, 20);
132 subs
.set_gather_level(1, 10);
135 log
.set_log_file("big");
136 log
.reopen_log_file();
137 for (int i
=0; i
<many
; i
++) {
139 if (subs
.should_gather(1, l
)) {
140 MutableEntry
e(l
, 1);
141 auto& s
= e
.get_ostream();
143 s
<< std::string(sizeof(e
) * 2, '-');
144 log
.submit_entry(std::move(e
));
151 TEST(Log
, ManyGather
)
154 subs
.set_log_level(1, 20);
155 subs
.set_gather_level(1, 1);
158 log
.set_log_file("big");
159 log
.reopen_log_file();
160 for (int i
=0; i
<many
; i
++) {
162 if (subs
.should_gather(1, l
))
163 log
.submit_entry(MutableEntry(l
, 1));
172 subs
.set_log_level(1, 20);
173 subs
.set_gather_level(1, 1);
176 log
.set_log_file("big");
177 log
.reopen_log_file();
180 MutableEntry
e(10, 1);
182 PrCtl unset_dumpable
;
183 log
.submit_entry(std::move(e
)); // this should segv
190 TEST(Log
, InternalSegv
)
192 ASSERT_DEATH(do_segv(), ".*");
198 subs
.set_log_level(1, 20);
199 subs
.set_gather_level(1, 10);
202 log
.set_log_file("big");
203 log
.reopen_log_file();
206 MutableEntry
e(l
, 1);
207 std::string
msg(10000000, 'a');
208 e
.get_ostream() << msg
;
209 log
.submit_entry(std::move(e
));
215 TEST(Log
, LargeFromSmallLog
)
218 subs
.set_log_level(1, 20);
219 subs
.set_gather_level(1, 10);
222 log
.set_log_file("big");
223 log
.reopen_log_file();
226 MutableEntry
e(l
, 1);
227 for (int i
= 0; i
< 1000000; i
++) {
228 std::string
msg(10, 'a');
229 e
.get_ostream() << msg
;
231 log
.submit_entry(std::move(e
));
237 // Make sure nothing bad happens when we switch
239 TEST(Log
, TimeSwitch
)
242 subs
.set_log_level(1, 20);
243 subs
.set_gather_level(1, 10);
246 log
.set_log_file("time_switch_log");
247 log
.reopen_log_file();
250 for (auto i
= 0U; i
< 300; ++i
) {
251 MutableEntry
e(l
, 1);
252 e
.get_ostream() << "SQUID THEFT! PUNISHABLE BY DEATH!";
253 log
.submit_entry(std::move(e
));
255 log
.set_coarse_timestamps(coarse
= !coarse
);
261 TEST(Log
, TimeFormat
)
263 static constexpr auto buflen
= 128u;
265 ceph::logging::log_clock clock
;
268 auto t
= clock
.now();
269 ceph::logging::append_time(t
, buf
, buflen
);
270 auto c
= std::strrchr(buf
, '.');
271 ASSERT_NE(c
, nullptr);
272 ASSERT_EQ(8u, strlen(c
+ 1));
276 auto t
= clock
.now();
277 ceph::logging::append_time(t
, buf
, buflen
);
278 auto c
= std::strrchr(buf
, '.');
279 ASSERT_NE(c
, nullptr);
280 ASSERT_EQ(11u, std::strlen(c
+ 1));
284 #define dout_subsys ceph_subsys_context
286 template <int depth
, int x
> struct do_log
288 void log(CephContext
* cct
);
291 template <int x
> struct do_log
<12, x
>
293 void log(CephContext
* cct
);
296 template<int depth
, int x
> void do_log
<depth
,x
>::log(CephContext
* cct
)
298 ldout(cct
, 20) << "Log depth=" << depth
<< " x=" << x
<< dendl
;
300 do_log
<depth
+1, x
*2> log
;
303 do_log
<depth
+1, x
*2+1> log
;
308 std::string
recursion(CephContext
* cct
)
310 ldout(cct
, 20) << "Preparing recursion string" << dendl
;
311 return "here-recursion";
314 template<int x
> void do_log
<12, x
>::log(CephContext
* cct
)
316 if ((rand() % 16) == 0) {
317 ldout(cct
, 20) << "End " << recursion(cct
) << "x=" << x
<< dendl
;
319 ldout(cct
, 20) << "End x=" << x
<< dendl
;
323 TEST(Log
, Speed_gather
)
326 g_ceph_context
->_conf
->subsys
.set_gather_level(ceph_subsys_context
, 30);
327 g_ceph_context
->_conf
->subsys
.set_log_level(ceph_subsys_context
, 0);
328 for (int i
=0; i
<100000;i
++) {
329 ldout(g_ceph_context
, 20) << "Iteration " << i
<< dendl
;
330 start
.log(g_ceph_context
);
334 TEST(Log
, Speed_nogather
)
337 g_ceph_context
->_conf
->subsys
.set_gather_level(ceph_subsys_context
, 0);
338 g_ceph_context
->_conf
->subsys
.set_log_level(ceph_subsys_context
, 0);
339 for (int i
=0; i
<100000;i
++) {
340 ldout(g_ceph_context
, 20) << "Iteration " << i
<< dendl
;
341 start
.log(g_ceph_context
);
345 TEST(Log
, GarbleRecovery
)
347 static const char* test_file
="log_for_moment";
349 Log
* saved
= g_ceph_context
->_log
;
350 Log
log(&g_ceph_context
->_conf
->subsys
);
353 log
.set_log_file(test_file
);
354 log
.reopen_log_file();
355 g_ceph_context
->_log
= &log
;
357 std::string
long_message(1000,'c');
358 ldout(g_ceph_context
, 0) << long_message
<< dendl
;
359 ldout(g_ceph_context
, 0) << "Prologue" << (std::streambuf
*)nullptr << long_message
<< dendl
;
360 ldout(g_ceph_context
, 0) << "Epitaph" << long_message
<< dendl
;
362 g_ceph_context
->_log
= saved
;
365 struct stat file_status
;
366 ASSERT_EQ(stat(test_file
, &file_status
), 0);
367 ASSERT_GT(file_status
.st_size
, 2000);
370 int main(int argc
, char **argv
)
372 auto args
= argv_to_vec(argc
, argv
);
374 auto cct
= global_init(nullptr, args
, CEPH_ENTITY_TYPE_CLIENT
,
375 CODE_ENVIRONMENT_UTILITY
,
376 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
377 common_init_finish(g_ceph_context
);
379 ::testing::InitGoogleTest(&argc
, argv
);
380 return RUN_ALL_TESTS();