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"
18 using namespace ceph::logging
;
23 subs
.set_log_level(0, 10);
24 subs
.set_gather_level(0, 10);
26 subs
.set_log_level(1, 20);
27 subs
.set_gather_level(1, 1);
29 subs
.set_log_level(2, 20);
30 subs
.set_gather_level(2, 2);
32 subs
.set_log_level(3, 10);
33 subs
.set_gather_level(3, 3);
38 log
.set_log_file("foo");
39 log
.reopen_log_file();
41 log
.set_stderr_level(5, -1);
44 for (int i
=0; i
<100; i
++) {
47 if (subs
.should_gather(sys
, l
)) {
48 MutableEntry
e(l
, sys
);
49 log
.submit_entry(std::move(e
));
63 subs
.set_log_level(1, 1);
64 subs
.set_gather_level(1, 1);
67 log
.set_log_file("foo");
68 log
.reopen_log_file();
73 auto& out
= e
.get_ostream();
74 out
<< (std::streambuf
*)nullptr;
75 EXPECT_TRUE(out
.bad()); // writing nullptr to a stream sets its badbit
76 log
.submit_entry(std::move(e
));
80 auto& out
= e
.get_ostream();
81 EXPECT_FALSE(out
.bad()); // should not see failures from previous log entry
83 log
.submit_entry(std::move(e
));
92 TEST(Log
, ManyNoGather
)
95 subs
.set_log_level(1, 1);
96 subs
.set_gather_level(1, 1);
99 log
.set_log_file("big");
100 log
.reopen_log_file();
101 for (int i
=0; i
<many
; i
++) {
103 if (subs
.should_gather(1, l
))
104 log
.submit_entry(MutableEntry(1, 0));
111 TEST(Log
, ManyGatherLog
)
114 subs
.set_log_level(1, 20);
115 subs
.set_gather_level(1, 10);
118 log
.set_log_file("big");
119 log
.reopen_log_file();
120 for (int i
=0; i
<many
; i
++) {
122 if (subs
.should_gather(1, l
)) {
123 MutableEntry
e(l
, 1);
124 e
.get_ostream() << "this is a long string asdf asdf asdf asdf asdf asdf asd fasd fasdf ";
125 log
.submit_entry(std::move(e
));
132 TEST(Log
, ManyGatherLogStackSpillover
)
135 subs
.set_log_level(1, 20);
136 subs
.set_gather_level(1, 10);
139 log
.set_log_file("big");
140 log
.reopen_log_file();
141 for (int i
=0; i
<many
; i
++) {
143 if (subs
.should_gather(1, l
)) {
144 MutableEntry
e(l
, 1);
145 auto& s
= e
.get_ostream();
147 s
<< std::string(sizeof(e
) * 2, '-');
148 log
.submit_entry(std::move(e
));
155 TEST(Log
, ManyGather
)
158 subs
.set_log_level(1, 20);
159 subs
.set_gather_level(1, 1);
162 log
.set_log_file("big");
163 log
.reopen_log_file();
164 for (int i
=0; i
<many
; i
++) {
166 if (subs
.should_gather(1, l
))
167 log
.submit_entry(MutableEntry(l
, 1));
173 static void readpipe(int fd
, int verify
)
176 /* Use larger buffer on receiver as Linux will allow pipes buffers to
177 * exceed PIPE_BUF. We can't avoid tearing due to small read buffers from
181 char buf
[65536] = "";
182 int rc
= read(fd
, buf
, (sizeof buf
) - 1);
185 } else if (rc
== -1) {
189 char* p
= strrchr(buf
, '\n');
190 /* verify no torn writes */
193 } else if (p
[1] != '\0') {
194 write(2, buf
, strlen(buf
));
203 TEST(Log
, StderrPipeAtomic
)
205 int pfd
[2] = {-1, -1};
212 } else if (pid
== (pid_t
)-1) {
218 subs
.set_log_level(1, 20);
219 subs
.set_gather_level(1, 10);
222 log
.set_log_file("");
223 log
.reopen_log_file();
224 log
.set_stderr_fd(pfd
[1]);
225 log
.set_stderr_level(1, 20);
226 /* -128 for prefix space */
227 for (int i
= 0; i
< PIPE_BUF
-128; i
++) {
228 MutableEntry
e(1, 1);
229 auto& s
= e
.get_ostream();
230 for (int j
= 0; j
< i
; j
++) {
235 log
.submit_entry(std::move(e
));
241 pid_t waited
= waitpid(pid
, &status
, 0);
242 ASSERT_EQ(pid
, waited
);
243 ASSERT_NE(WIFEXITED(status
), 0);
244 ASSERT_EQ(WEXITSTATUS(status
), 0);
247 TEST(Log
, StderrPipeBig
)
249 int pfd
[2] = {-1, -1};
254 /* no verification as some reads will be torn due to size > PIPE_BUF */
257 } else if (pid
== (pid_t
)-1) {
263 subs
.set_log_level(1, 20);
264 subs
.set_gather_level(1, 10);
267 log
.set_log_file("");
268 log
.reopen_log_file();
269 log
.set_stderr_fd(pfd
[1]);
270 log
.set_stderr_level(1, 20);
271 /* -128 for prefix space */
272 for (int i
= 0; i
< PIPE_BUF
*2; i
++) {
273 MutableEntry
e(1, 1);
274 auto& s
= e
.get_ostream();
275 for (int j
= 0; j
< i
; j
++) {
280 log
.submit_entry(std::move(e
));
286 pid_t waited
= waitpid(pid
, &status
, 0);
287 ASSERT_EQ(pid
, waited
);
288 ASSERT_NE(WIFEXITED(status
), 0);
289 ASSERT_EQ(WEXITSTATUS(status
), 0);
295 subs
.set_log_level(1, 20);
296 subs
.set_gather_level(1, 1);
299 log
.set_log_file("big");
300 log
.reopen_log_file();
303 MutableEntry
e(10, 1);
305 PrCtl unset_dumpable
;
306 log
.submit_entry(std::move(e
)); // this should segv
313 TEST(Log
, InternalSegv
)
315 ASSERT_DEATH(do_segv(), ".*");
321 subs
.set_log_level(1, 20);
322 subs
.set_gather_level(1, 10);
325 log
.set_log_file("big");
326 log
.reopen_log_file();
329 MutableEntry
e(l
, 1);
330 std::string
msg(10000000, 'a');
331 e
.get_ostream() << msg
;
332 log
.submit_entry(std::move(e
));
338 TEST(Log
, LargeFromSmallLog
)
341 subs
.set_log_level(1, 20);
342 subs
.set_gather_level(1, 10);
345 log
.set_log_file("big");
346 log
.reopen_log_file();
349 MutableEntry
e(l
, 1);
350 for (int i
= 0; i
< 1000000; i
++) {
351 std::string
msg(10, 'a');
352 e
.get_ostream() << msg
;
354 log
.submit_entry(std::move(e
));
360 // Make sure nothing bad happens when we switch
362 TEST(Log
, TimeSwitch
)
365 subs
.set_log_level(1, 20);
366 subs
.set_gather_level(1, 10);
369 log
.set_log_file("time_switch_log");
370 log
.reopen_log_file();
373 for (auto i
= 0U; i
< 300; ++i
) {
374 MutableEntry
e(l
, 1);
375 e
.get_ostream() << "SQUID THEFT! PUNISHABLE BY DEATH!";
376 log
.submit_entry(std::move(e
));
378 log
.set_coarse_timestamps(coarse
= !coarse
);
384 TEST(Log
, TimeFormat
)
386 static constexpr auto buflen
= 128u;
388 ceph::logging::log_clock clock
;
391 auto t
= clock
.now();
392 ceph::logging::append_time(t
, buf
, buflen
);
393 auto c
= std::strrchr(buf
, '.');
394 ASSERT_NE(c
, nullptr);
395 ASSERT_EQ(8u, strlen(c
+ 1));
399 auto t
= clock
.now();
400 ceph::logging::append_time(t
, buf
, buflen
);
401 auto c
= std::strrchr(buf
, '.');
402 ASSERT_NE(c
, nullptr);
403 ASSERT_EQ(11u, std::strlen(c
+ 1));
407 #define dout_subsys ceph_subsys_context
409 template <int depth
, int x
> struct do_log
411 void log(CephContext
* cct
);
414 template <int x
> struct do_log
<12, x
>
416 void log(CephContext
* cct
);
419 template<int depth
, int x
> void do_log
<depth
,x
>::log(CephContext
* cct
)
421 ldout(cct
, 20) << "Log depth=" << depth
<< " x=" << x
<< dendl
;
423 do_log
<depth
+1, x
*2> log
;
426 do_log
<depth
+1, x
*2+1> log
;
431 std::string
recursion(CephContext
* cct
)
433 ldout(cct
, 20) << "Preparing recursion string" << dendl
;
434 return "here-recursion";
437 template<int x
> void do_log
<12, x
>::log(CephContext
* cct
)
439 if ((rand() % 16) == 0) {
440 ldout(cct
, 20) << "End " << recursion(cct
) << "x=" << x
<< dendl
;
442 ldout(cct
, 20) << "End x=" << x
<< dendl
;
446 TEST(Log
, Speed_gather
)
449 g_ceph_context
->_conf
->subsys
.set_gather_level(ceph_subsys_context
, 30);
450 g_ceph_context
->_conf
->subsys
.set_log_level(ceph_subsys_context
, 0);
451 for (int i
=0; i
<100000;i
++) {
452 ldout(g_ceph_context
, 20) << "Iteration " << i
<< dendl
;
453 start
.log(g_ceph_context
);
457 TEST(Log
, Speed_nogather
)
460 g_ceph_context
->_conf
->subsys
.set_gather_level(ceph_subsys_context
, 0);
461 g_ceph_context
->_conf
->subsys
.set_log_level(ceph_subsys_context
, 0);
462 for (int i
=0; i
<100000;i
++) {
463 ldout(g_ceph_context
, 20) << "Iteration " << i
<< dendl
;
464 start
.log(g_ceph_context
);
468 TEST(Log
, GarbleRecovery
)
470 static const char* test_file
="log_for_moment";
472 Log
* saved
= g_ceph_context
->_log
;
473 Log
log(&g_ceph_context
->_conf
->subsys
);
476 log
.set_log_file(test_file
);
477 log
.reopen_log_file();
478 g_ceph_context
->_log
= &log
;
480 std::string
long_message(1000,'c');
481 ldout(g_ceph_context
, 0) << long_message
<< dendl
;
482 ldout(g_ceph_context
, 0) << "Prologue" << (std::streambuf
*)nullptr << long_message
<< dendl
;
483 ldout(g_ceph_context
, 0) << "Epitaph" << long_message
<< dendl
;
485 g_ceph_context
->_log
= saved
;
488 struct stat file_status
;
489 ASSERT_EQ(stat(test_file
, &file_status
), 0);
490 ASSERT_GT(file_status
.st_size
, 2000);
493 int main(int argc
, char **argv
)
495 auto args
= argv_to_vec(argc
, argv
);
497 auto cct
= global_init(nullptr, args
, CEPH_ENTITY_TYPE_CLIENT
,
498 CODE_ENVIRONMENT_UTILITY
,
499 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
500 common_init_finish(g_ceph_context
);
502 ::testing::InitGoogleTest(&argc
, argv
);
503 return RUN_ALL_TESTS();