auto_roll_logger_test.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. #include "logging/auto_roll_logger.h"
  7. #include <sys/stat.h>
  8. #include <algorithm>
  9. #include <cmath>
  10. #include <fstream>
  11. #include <iostream>
  12. #include <iterator>
  13. #include <string>
  14. #include <thread>
  15. #include <vector>
  16. #include "db/db_test_util.h"
  17. #include "env/emulated_clock.h"
  18. #include "logging/env_logger.h"
  19. #include "logging/logging.h"
  20. #include "port/port.h"
  21. #include "rocksdb/db.h"
  22. #include "rocksdb/file_system.h"
  23. #include "rocksdb/system_clock.h"
  24. #include "test_util/sync_point.h"
  25. #include "test_util/testharness.h"
  26. #include "test_util/testutil.h"
  27. namespace ROCKSDB_NAMESPACE {
  28. // In this test we only want to Log some simple log message with
  29. // no format. LogMessage() provides such a simple interface and
  30. // avoids the [format-security] warning which occurs when you
  31. // call ROCKS_LOG_INFO(logger, log_message) directly.
  32. namespace {
  33. void LogMessage(Logger* logger, const char* message) {
  34. ROCKS_LOG_INFO(logger, "%s", message);
  35. }
  36. void LogMessage(const InfoLogLevel log_level, Logger* logger,
  37. const char* message) {
  38. Log(log_level, logger, "%s", message);
  39. }
  40. } // namespace
  41. class AutoRollLoggerTest : public testing::Test {
  42. public:
  43. static void InitTestDb() {
  44. // TODO replace the `system` calls with Env/FileSystem APIs.
  45. #ifdef OS_WIN
  46. // Replace all slashes in the path so windows CompSpec does not
  47. // become confused
  48. std::string testDbDir(kTestDbDir);
  49. std::replace_if(
  50. testDbDir.begin(), testDbDir.end(), [](char ch) { return ch == '/'; },
  51. '\\');
  52. std::string deleteDbDirCmd =
  53. "if exist " + testDbDir + " rd /s /q " + testDbDir;
  54. ASSERT_TRUE(system(deleteDbDirCmd.c_str()) == 0);
  55. std::string testDir(kTestDir);
  56. std::replace_if(
  57. testDir.begin(), testDir.end(), [](char ch) { return ch == '/'; },
  58. '\\');
  59. std::string deleteCmd = "if exist " + testDir + " rd /s /q " + testDir;
  60. #else
  61. std::string deleteCmd = "rm -rf " + kTestDir + " " + kTestDbDir;
  62. #endif
  63. ASSERT_TRUE(system(deleteCmd.c_str()) == 0);
  64. ASSERT_OK(Env::Default()->CreateDir(kTestDir));
  65. ASSERT_OK(Env::Default()->CreateDir(kTestDbDir));
  66. }
  67. void RollLogFileBySizeTest(AutoRollLogger* logger, size_t log_max_size,
  68. const std::string& log_message);
  69. void RollLogFileByTimeTest(const std::shared_ptr<FileSystem>& fs,
  70. const std::shared_ptr<SystemClock>& sc,
  71. AutoRollLogger* logger, size_t time,
  72. const std::string& log_message);
  73. // return list of files under kTestDir that contains "LOG"
  74. std::vector<std::string> GetLogFiles() {
  75. std::vector<std::string> ret;
  76. std::vector<std::string> files;
  77. Status s = default_env->GetChildren(kTestDir, &files);
  78. // Should call ASSERT_OK() here but it doesn't compile. It's not
  79. // worth the time figuring out why.
  80. EXPECT_TRUE(s.ok());
  81. for (const auto& f : files) {
  82. if (f.find("LOG") != std::string::npos) {
  83. ret.push_back(f);
  84. }
  85. }
  86. return ret;
  87. }
  88. // Delete all log files under kTestDir
  89. void CleanupLogFiles() {
  90. for (const std::string& f : GetLogFiles()) {
  91. ASSERT_OK(default_env->DeleteFile(kTestDir + "/" + f));
  92. }
  93. }
  94. void RollNTimesBySize(Logger* auto_roll_logger, size_t file_num,
  95. size_t max_log_file_size) {
  96. // Roll the log 4 times, and it will trim to 3 files.
  97. std::string dummy_large_string;
  98. dummy_large_string.assign(max_log_file_size, '=');
  99. auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
  100. for (size_t i = 0; i < file_num + 1; i++) {
  101. // Log enough bytes to trigger at least one roll.
  102. LogMessage(auto_roll_logger, dummy_large_string.c_str());
  103. LogMessage(auto_roll_logger, "");
  104. }
  105. }
  106. static const std::string kSampleMessage;
  107. static const std::string kTestDir;
  108. static const std::string kTestDbDir;
  109. static const std::string kLogFile;
  110. static Env* default_env;
  111. };
  112. const std::string AutoRollLoggerTest::kSampleMessage(
  113. "this is the message to be written to the log file!!");
  114. const std::string AutoRollLoggerTest::kTestDir(
  115. test::PerThreadDBPath("db_log_test"));
  116. const std::string AutoRollLoggerTest::kTestDbDir(
  117. test::PerThreadDBPath("db_log_test_db"));
  118. const std::string AutoRollLoggerTest::kLogFile(
  119. test::PerThreadDBPath("db_log_test") + "/LOG");
  120. Env* AutoRollLoggerTest::default_env = Env::Default();
  121. void AutoRollLoggerTest::RollLogFileBySizeTest(AutoRollLogger* logger,
  122. size_t log_max_size,
  123. const std::string& log_message) {
  124. logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
  125. ASSERT_EQ(InfoLogLevel::INFO_LEVEL, logger->GetInfoLogLevel());
  126. ASSERT_EQ(InfoLogLevel::INFO_LEVEL,
  127. logger->TEST_inner_logger()->GetInfoLogLevel());
  128. // measure the size of each message, which is supposed
  129. // to be equal or greater than log_message.size()
  130. LogMessage(logger, log_message.c_str());
  131. size_t message_size = logger->GetLogFileSize();
  132. size_t current_log_size = message_size;
  133. // Test the cases when the log file will not be rolled.
  134. while (current_log_size + message_size < log_max_size) {
  135. LogMessage(logger, log_message.c_str());
  136. current_log_size += message_size;
  137. ASSERT_EQ(current_log_size, logger->GetLogFileSize());
  138. }
  139. // Now the log file will be rolled
  140. LogMessage(logger, log_message.c_str());
  141. // Since rotation is checked before actual logging, we need to
  142. // trigger the rotation by logging another message.
  143. LogMessage(logger, log_message.c_str());
  144. ASSERT_TRUE(message_size == logger->GetLogFileSize());
  145. }
  146. void AutoRollLoggerTest::RollLogFileByTimeTest(
  147. const std::shared_ptr<FileSystem>& fs,
  148. const std::shared_ptr<SystemClock>& sc, AutoRollLogger* logger, size_t time,
  149. const std::string& log_message) {
  150. uint64_t expected_ctime;
  151. uint64_t actual_ctime;
  152. uint64_t total_log_size;
  153. EXPECT_OK(fs->GetFileSize(kLogFile, IOOptions(), &total_log_size, nullptr));
  154. expected_ctime = logger->TEST_ctime();
  155. logger->SetCallNowMicrosEveryNRecords(0);
  156. // -- Write to the log for several times, which is supposed
  157. // to be finished before time.
  158. for (int i = 0; i < 10; ++i) {
  159. sc->SleepForMicroseconds(50000);
  160. LogMessage(logger, log_message.c_str());
  161. EXPECT_OK(logger->GetStatus());
  162. // Make sure we always write to the same log file (by
  163. // checking the create time);
  164. actual_ctime = logger->TEST_ctime();
  165. // Also make sure the log size is increasing.
  166. EXPECT_EQ(expected_ctime, actual_ctime);
  167. EXPECT_GT(logger->GetLogFileSize(), total_log_size);
  168. total_log_size = logger->GetLogFileSize();
  169. }
  170. // -- Make the log file expire
  171. sc->SleepForMicroseconds(static_cast<int>(time * 1000000));
  172. LogMessage(logger, log_message.c_str());
  173. // At this time, the new log file should be created.
  174. actual_ctime = logger->TEST_ctime();
  175. EXPECT_LT(expected_ctime, actual_ctime);
  176. EXPECT_LT(logger->GetLogFileSize(), total_log_size);
  177. }
  178. TEST_F(AutoRollLoggerTest, RollLogFileBySize) {
  179. InitTestDb();
  180. size_t log_max_size = 1024 * 5;
  181. size_t keep_log_file_num = 10;
  182. AutoRollLogger logger(FileSystem::Default(), SystemClock::Default(), kTestDir,
  183. "", log_max_size, 0, keep_log_file_num);
  184. RollLogFileBySizeTest(&logger, log_max_size,
  185. kSampleMessage + ":RollLogFileBySize");
  186. }
  187. TEST_F(AutoRollLoggerTest, RollLogFileByTime) {
  188. auto nsc =
  189. std::make_shared<EmulatedSystemClock>(SystemClock::Default(), true);
  190. size_t time = 2;
  191. size_t log_size = 1024 * 5;
  192. size_t keep_log_file_num = 10;
  193. InitTestDb();
  194. // -- Test the existence of file during the server restart.
  195. ASSERT_EQ(Status::NotFound(), default_env->FileExists(kLogFile));
  196. AutoRollLogger logger(default_env->GetFileSystem(), nsc, kTestDir, "",
  197. log_size, time, keep_log_file_num);
  198. ASSERT_OK(default_env->FileExists(kLogFile));
  199. RollLogFileByTimeTest(default_env->GetFileSystem(), nsc, &logger, time,
  200. kSampleMessage + ":RollLogFileByTime");
  201. }
  202. TEST_F(AutoRollLoggerTest, SetInfoLogLevel) {
  203. InitTestDb();
  204. Options options;
  205. options.info_log_level = InfoLogLevel::FATAL_LEVEL;
  206. options.max_log_file_size = 1024;
  207. std::shared_ptr<Logger> logger;
  208. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  209. auto* auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());
  210. ASSERT_NE(nullptr, auto_roll_logger);
  211. ASSERT_EQ(InfoLogLevel::FATAL_LEVEL, auto_roll_logger->GetInfoLogLevel());
  212. ASSERT_EQ(InfoLogLevel::FATAL_LEVEL,
  213. auto_roll_logger->TEST_inner_logger()->GetInfoLogLevel());
  214. auto_roll_logger->SetInfoLogLevel(InfoLogLevel::DEBUG_LEVEL);
  215. ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL, auto_roll_logger->GetInfoLogLevel());
  216. ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL, logger->GetInfoLogLevel());
  217. ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL,
  218. auto_roll_logger->TEST_inner_logger()->GetInfoLogLevel());
  219. }
  220. TEST_F(AutoRollLoggerTest, OpenLogFilesMultipleTimesWithOptionLog_max_size) {
  221. // If only 'log_max_size' options is specified, then every time
  222. // when rocksdb is restarted, a new empty log file will be created.
  223. InitTestDb();
  224. // WORKAROUND:
  225. // avoid complier's complaint of "comparison between signed
  226. // and unsigned integer expressions" because literal 0 is
  227. // treated as "singed".
  228. size_t kZero = 0;
  229. size_t log_size = 1024;
  230. size_t keep_log_file_num = 10;
  231. AutoRollLogger* logger =
  232. new AutoRollLogger(FileSystem::Default(), SystemClock::Default(),
  233. kTestDir, "", log_size, 0, keep_log_file_num);
  234. LogMessage(logger, kSampleMessage.c_str());
  235. ASSERT_GT(logger->GetLogFileSize(), kZero);
  236. delete logger;
  237. // reopens the log file and an empty log file will be created.
  238. logger = new AutoRollLogger(FileSystem::Default(), SystemClock::Default(),
  239. kTestDir, "", log_size, 0, 10);
  240. ASSERT_EQ(logger->GetLogFileSize(), kZero);
  241. delete logger;
  242. }
  243. TEST_F(AutoRollLoggerTest, CompositeRollByTimeAndSizeLogger) {
  244. size_t time = 2, log_max_size = 1024 * 5;
  245. size_t keep_log_file_num = 10;
  246. InitTestDb();
  247. auto nsc =
  248. std::make_shared<EmulatedSystemClock>(SystemClock::Default(), true);
  249. AutoRollLogger logger(FileSystem::Default(), nsc, kTestDir, "", log_max_size,
  250. time, keep_log_file_num);
  251. // Test the ability to roll by size
  252. RollLogFileBySizeTest(&logger, log_max_size,
  253. kSampleMessage + ":CompositeRollByTimeAndSizeLogger");
  254. // Test the ability to roll by Time
  255. RollLogFileByTimeTest(FileSystem::Default(), nsc, &logger, time,
  256. kSampleMessage + ":CompositeRollByTimeAndSizeLogger");
  257. }
  258. #ifndef OS_WIN
  259. // TODO: does not build for Windows because of EnvLogger use below. Need to
  260. // port
  261. TEST_F(AutoRollLoggerTest, CreateLoggerFromOptions) {
  262. DBOptions options;
  263. auto nsc =
  264. std::make_shared<EmulatedSystemClock>(SystemClock::Default(), true);
  265. std::unique_ptr<Env> nse(new CompositeEnvWrapper(Env::Default(), nsc));
  266. std::shared_ptr<Logger> logger;
  267. // Normal logger
  268. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  269. ASSERT_TRUE(dynamic_cast<EnvLogger*>(logger.get()));
  270. // Only roll by size
  271. InitTestDb();
  272. options.max_log_file_size = 1024;
  273. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  274. AutoRollLogger* auto_roll_logger =
  275. dynamic_cast<AutoRollLogger*>(logger.get());
  276. ASSERT_TRUE(auto_roll_logger);
  277. RollLogFileBySizeTest(auto_roll_logger, options.max_log_file_size,
  278. kSampleMessage + ":CreateLoggerFromOptions - size");
  279. // Only roll by Time
  280. options.env = nse.get();
  281. InitTestDb();
  282. options.max_log_file_size = 0;
  283. options.log_file_time_to_roll = 2;
  284. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  285. auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());
  286. RollLogFileByTimeTest(options.env->GetFileSystem(), nsc, auto_roll_logger,
  287. options.log_file_time_to_roll,
  288. kSampleMessage + ":CreateLoggerFromOptions - time");
  289. // roll by both Time and size
  290. InitTestDb();
  291. options.max_log_file_size = 1024 * 5;
  292. options.log_file_time_to_roll = 2;
  293. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  294. auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());
  295. RollLogFileBySizeTest(auto_roll_logger, options.max_log_file_size,
  296. kSampleMessage + ":CreateLoggerFromOptions - both");
  297. RollLogFileByTimeTest(options.env->GetFileSystem(), nsc, auto_roll_logger,
  298. options.log_file_time_to_roll,
  299. kSampleMessage + ":CreateLoggerFromOptions - both");
  300. // Set keep_log_file_num
  301. {
  302. const size_t kFileNum = 3;
  303. InitTestDb();
  304. options.max_log_file_size = 512;
  305. options.log_file_time_to_roll = 2;
  306. options.keep_log_file_num = kFileNum;
  307. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  308. auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());
  309. // Roll the log 4 times, and it will trim to 3 files.
  310. std::string dummy_large_string;
  311. dummy_large_string.assign(options.max_log_file_size, '=');
  312. auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
  313. for (size_t i = 0; i < kFileNum + 1; i++) {
  314. // Log enough bytes to trigger at least one roll.
  315. LogMessage(auto_roll_logger, dummy_large_string.c_str());
  316. LogMessage(auto_roll_logger, "");
  317. }
  318. std::vector<std::string> files = GetLogFiles();
  319. ASSERT_EQ(kFileNum, files.size());
  320. CleanupLogFiles();
  321. }
  322. // Set keep_log_file_num and dbname is different from
  323. // db_log_dir.
  324. {
  325. const size_t kFileNum = 3;
  326. InitTestDb();
  327. options.max_log_file_size = 512;
  328. options.log_file_time_to_roll = 2;
  329. options.keep_log_file_num = kFileNum;
  330. options.db_log_dir = kTestDir;
  331. ASSERT_OK(CreateLoggerFromOptions(kTestDbDir, options, &logger));
  332. auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());
  333. // Roll the log 4 times, and it will trim to 3 files.
  334. std::string dummy_large_string;
  335. dummy_large_string.assign(options.max_log_file_size, '=');
  336. auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
  337. for (size_t i = 0; i < kFileNum + 1; i++) {
  338. // Log enough bytes to trigger at least one roll.
  339. LogMessage(auto_roll_logger, dummy_large_string.c_str());
  340. LogMessage(auto_roll_logger, "");
  341. }
  342. std::vector<std::string> files = GetLogFiles();
  343. ASSERT_EQ(kFileNum, files.size());
  344. for (const auto& f : files) {
  345. ASSERT_TRUE(f.find("db_log_test_db") != std::string::npos);
  346. }
  347. // Cleaning up those files.
  348. CleanupLogFiles();
  349. }
  350. }
  351. TEST_F(AutoRollLoggerTest, AutoDeleting) {
  352. for (int attempt = 0; attempt < 2; attempt++) {
  353. // In the first attemp, db_log_dir is not set, while in the
  354. // second it is set.
  355. std::string dbname = (attempt == 0) ? kTestDir : "/test/dummy/dir";
  356. std::string db_log_dir = (attempt == 0) ? "" : kTestDir;
  357. InitTestDb();
  358. const size_t kMaxFileSize = 512;
  359. {
  360. size_t log_num = 8;
  361. AutoRollLogger logger(FileSystem::Default(), SystemClock::Default(),
  362. dbname, db_log_dir, kMaxFileSize, 0, log_num);
  363. RollNTimesBySize(&logger, log_num, kMaxFileSize);
  364. ASSERT_EQ(log_num, GetLogFiles().size());
  365. }
  366. // Shrink number of files
  367. {
  368. size_t log_num = 5;
  369. AutoRollLogger logger(FileSystem::Default(), SystemClock::Default(),
  370. dbname, db_log_dir, kMaxFileSize, 0, log_num);
  371. ASSERT_EQ(log_num, GetLogFiles().size());
  372. RollNTimesBySize(&logger, 3, kMaxFileSize);
  373. ASSERT_EQ(log_num, GetLogFiles().size());
  374. }
  375. // Increase number of files again.
  376. {
  377. size_t log_num = 7;
  378. AutoRollLogger logger(FileSystem::Default(), SystemClock::Default(),
  379. dbname, db_log_dir, kMaxFileSize, 0, log_num);
  380. ASSERT_EQ(6, GetLogFiles().size());
  381. RollNTimesBySize(&logger, 3, kMaxFileSize);
  382. ASSERT_EQ(log_num, GetLogFiles().size());
  383. }
  384. CleanupLogFiles();
  385. }
  386. }
  387. TEST_F(AutoRollLoggerTest, LogFlushWhileRolling) {
  388. DBOptions options;
  389. std::shared_ptr<Logger> logger;
  390. InitTestDb();
  391. options.max_log_file_size = 1024 * 5;
  392. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  393. AutoRollLogger* auto_roll_logger =
  394. dynamic_cast<AutoRollLogger*>(logger.get());
  395. ASSERT_TRUE(auto_roll_logger);
  396. ROCKSDB_NAMESPACE::port::Thread flush_thread;
  397. // Notes:
  398. // (1) Need to pin the old logger before beginning the roll, as rolling grabs
  399. // the mutex, which would prevent us from accessing the old logger. This
  400. // also marks flush_thread with AutoRollLogger::Flush:PinnedLogger.
  401. // (2) New logger will be cut in AutoRollLogger::RollLogFile only when flush
  402. // is completed and reference to pinned logger is released.
  403. // (3) EnvLogger::Flush() happens in both threads but its SyncPoints only
  404. // are enabled in flush_thread (the one pinning the old logger).
  405. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependencyAndMarkers(
  406. {{"AutoRollLogger::Flush:PinnedLogger",
  407. "AutoRollLoggerTest::LogFlushWhileRolling:PreRollAndPostThreadInit"}},
  408. {{"AutoRollLogger::Flush:PinnedLogger", "EnvLogger::Flush:Begin1"},
  409. {"AutoRollLogger::Flush:PinnedLogger", "EnvLogger::Flush:Begin2"}});
  410. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  411. flush_thread = port::Thread([&]() { auto_roll_logger->Flush(); });
  412. TEST_SYNC_POINT(
  413. "AutoRollLoggerTest::LogFlushWhileRolling:PreRollAndPostThreadInit");
  414. RollLogFileBySizeTest(auto_roll_logger, options.max_log_file_size,
  415. kSampleMessage + ":LogFlushWhileRolling");
  416. flush_thread.join();
  417. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  418. }
  419. #endif // OS_WIN
  420. TEST_F(AutoRollLoggerTest, InfoLogLevel) {
  421. InitTestDb();
  422. size_t log_size = 8192;
  423. size_t log_lines = 0;
  424. // an extra-scope to force the AutoRollLogger to flush the log file when it
  425. // becomes out of scope.
  426. {
  427. AutoRollLogger logger(FileSystem::Default(), SystemClock::Default(),
  428. kTestDir, "", log_size, 0, 10);
  429. for (int log_level = InfoLogLevel::HEADER_LEVEL;
  430. log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {
  431. logger.SetInfoLogLevel((InfoLogLevel)log_level);
  432. for (int log_type = InfoLogLevel::DEBUG_LEVEL;
  433. log_type <= InfoLogLevel::HEADER_LEVEL; log_type++) {
  434. // log messages with log level smaller than log_level will not be
  435. // logged.
  436. LogMessage((InfoLogLevel)log_type, &logger, kSampleMessage.c_str());
  437. }
  438. log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;
  439. }
  440. for (int log_level = InfoLogLevel::HEADER_LEVEL;
  441. log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {
  442. logger.SetInfoLogLevel((InfoLogLevel)log_level);
  443. // again, messages with level smaller than log_level will not be logged.
  444. ROCKS_LOG_HEADER(&logger, "%s", kSampleMessage.c_str());
  445. ROCKS_LOG_DEBUG(&logger, "%s", kSampleMessage.c_str());
  446. ROCKS_LOG_INFO(&logger, "%s", kSampleMessage.c_str());
  447. ROCKS_LOG_WARN(&logger, "%s", kSampleMessage.c_str());
  448. ROCKS_LOG_ERROR(&logger, "%s", kSampleMessage.c_str());
  449. ROCKS_LOG_FATAL(&logger, "%s", kSampleMessage.c_str());
  450. log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;
  451. }
  452. }
  453. std::ifstream inFile(AutoRollLoggerTest::kLogFile.c_str());
  454. size_t lines = std::count(std::istreambuf_iterator<char>(inFile),
  455. std::istreambuf_iterator<char>(), '\n');
  456. ASSERT_EQ(log_lines, lines);
  457. inFile.close();
  458. }
  459. TEST_F(AutoRollLoggerTest, Close) {
  460. InitTestDb();
  461. size_t log_size = 8192;
  462. size_t log_lines = 0;
  463. AutoRollLogger logger(FileSystem::Default(), SystemClock::Default(), kTestDir,
  464. "", log_size, 0, 10);
  465. for (int log_level = InfoLogLevel::HEADER_LEVEL;
  466. log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {
  467. logger.SetInfoLogLevel((InfoLogLevel)log_level);
  468. for (int log_type = InfoLogLevel::DEBUG_LEVEL;
  469. log_type <= InfoLogLevel::HEADER_LEVEL; log_type++) {
  470. // log messages with log level smaller than log_level will not be
  471. // logged.
  472. LogMessage((InfoLogLevel)log_type, &logger, kSampleMessage.c_str());
  473. }
  474. log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;
  475. }
  476. for (int log_level = InfoLogLevel::HEADER_LEVEL;
  477. log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {
  478. logger.SetInfoLogLevel((InfoLogLevel)log_level);
  479. // again, messages with level smaller than log_level will not be logged.
  480. ROCKS_LOG_HEADER(&logger, "%s", kSampleMessage.c_str());
  481. ROCKS_LOG_DEBUG(&logger, "%s", kSampleMessage.c_str());
  482. ROCKS_LOG_INFO(&logger, "%s", kSampleMessage.c_str());
  483. ROCKS_LOG_WARN(&logger, "%s", kSampleMessage.c_str());
  484. ROCKS_LOG_ERROR(&logger, "%s", kSampleMessage.c_str());
  485. ROCKS_LOG_FATAL(&logger, "%s", kSampleMessage.c_str());
  486. log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;
  487. }
  488. ASSERT_EQ(logger.Close(), Status::OK());
  489. std::ifstream inFile(AutoRollLoggerTest::kLogFile.c_str());
  490. size_t lines = std::count(std::istreambuf_iterator<char>(inFile),
  491. std::istreambuf_iterator<char>(), '\n');
  492. ASSERT_EQ(log_lines, lines);
  493. inFile.close();
  494. }
  495. // Test the logger Header function for roll over logs
  496. // We expect the new logs creates as roll over to carry the headers specified
  497. static std::vector<std::string> GetOldFileNames(const std::string& path) {
  498. std::vector<std::string> ret;
  499. const std::string dirname = path.substr(/*start=*/0, path.find_last_of('/'));
  500. const std::string fname = path.substr(path.find_last_of('/') + 1);
  501. std::vector<std::string> children;
  502. EXPECT_OK(Env::Default()->GetChildren(dirname, &children));
  503. // We know that the old log files are named [path]<something>
  504. // Return all entities that match the pattern
  505. for (auto& child : children) {
  506. if (fname != child && child.find(fname) == 0) {
  507. ret.push_back(dirname + "/" + child);
  508. }
  509. }
  510. return ret;
  511. }
  512. TEST_F(AutoRollLoggerTest, LogHeaderTest) {
  513. static const size_t MAX_HEADERS = 10;
  514. static const size_t LOG_MAX_SIZE = 1024 * 5;
  515. static const std::string HEADER_STR = "Log header line";
  516. // test_num == 0 -> standard call to Header()
  517. // test_num == 1 -> call to Log() with InfoLogLevel::HEADER_LEVEL
  518. for (int test_num = 0; test_num < 2; test_num++) {
  519. InitTestDb();
  520. AutoRollLogger logger(FileSystem::Default(), SystemClock::Default(),
  521. kTestDir, /*db_log_dir=*/"", LOG_MAX_SIZE,
  522. /*log_file_time_to_roll=*/0,
  523. /*keep_log_file_num=*/10);
  524. if (test_num == 0) {
  525. // Log some headers explicitly using Header()
  526. for (size_t i = 0; i < MAX_HEADERS; i++) {
  527. Header(&logger, "%s %" ROCKSDB_PRIszt, HEADER_STR.c_str(), i);
  528. }
  529. } else if (test_num == 1) {
  530. // HEADER_LEVEL should make this behave like calling Header()
  531. for (size_t i = 0; i < MAX_HEADERS; i++) {
  532. ROCKS_LOG_HEADER(&logger, "%s %" ROCKSDB_PRIszt, HEADER_STR.c_str(), i);
  533. }
  534. }
  535. const std::string newfname = logger.TEST_log_fname();
  536. // Log enough data to cause a roll over
  537. int i = 0;
  538. for (size_t iter = 0; iter < 2; iter++) {
  539. while (logger.GetLogFileSize() < LOG_MAX_SIZE) {
  540. Info(&logger, (kSampleMessage + ":LogHeaderTest line %d").c_str(), i);
  541. ++i;
  542. }
  543. Info(&logger, "Rollover");
  544. }
  545. // Flush the log for the latest file
  546. LogFlush(&logger);
  547. const auto oldfiles = GetOldFileNames(newfname);
  548. ASSERT_EQ(oldfiles.size(), (size_t)2);
  549. for (auto& oldfname : oldfiles) {
  550. // verify that the files rolled over
  551. ASSERT_NE(oldfname, newfname);
  552. // verify that the old log contains all the header logs
  553. ASSERT_EQ(test::GetLinesCount(oldfname, HEADER_STR), MAX_HEADERS);
  554. }
  555. }
  556. }
  557. TEST_F(AutoRollLoggerTest, LogFileExistence) {
  558. ROCKSDB_NAMESPACE::DB* db;
  559. ROCKSDB_NAMESPACE::Options options;
  560. #ifdef OS_WIN
  561. // Replace all slashes in the path so windows CompSpec does not
  562. // become confused
  563. std::string testDir(kTestDir);
  564. std::replace_if(
  565. testDir.begin(), testDir.end(), [](char ch) { return ch == '/'; }, '\\');
  566. std::string deleteCmd = "if exist " + testDir + " rd /s /q " + testDir;
  567. #else
  568. std::string deleteCmd = "rm -rf " + kTestDir;
  569. #endif
  570. ASSERT_EQ(system(deleteCmd.c_str()), 0);
  571. options.max_log_file_size = 100 * 1024 * 1024;
  572. options.create_if_missing = true;
  573. ASSERT_OK(ROCKSDB_NAMESPACE::DB::Open(options, kTestDir, &db));
  574. ASSERT_OK(default_env->FileExists(kLogFile));
  575. delete db;
  576. }
  577. TEST_F(AutoRollLoggerTest, FileCreateFailure) {
  578. Options options;
  579. options.max_log_file_size = 100 * 1024 * 1024;
  580. options.db_log_dir = "/a/dir/does/not/exist/at/all";
  581. std::shared_ptr<Logger> logger;
  582. ASSERT_NOK(CreateLoggerFromOptions("", options, &logger));
  583. ASSERT_TRUE(!logger);
  584. }
  585. TEST_F(AutoRollLoggerTest, RenameOnlyWhenExists) {
  586. InitTestDb();
  587. SpecialEnv env(Env::Default());
  588. Options options;
  589. options.env = &env;
  590. // Originally no LOG exists. Should not see a rename.
  591. {
  592. std::shared_ptr<Logger> logger;
  593. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  594. ASSERT_EQ(0, env.rename_count_);
  595. }
  596. // Now a LOG exists. Create a new one should see a rename.
  597. {
  598. std::shared_ptr<Logger> logger;
  599. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  600. ASSERT_EQ(1, env.rename_count_);
  601. }
  602. }
  603. TEST_F(AutoRollLoggerTest, RenameError) {
  604. InitTestDb();
  605. SpecialEnv env(Env::Default());
  606. env.rename_error_ = true;
  607. Options options;
  608. options.env = &env;
  609. // Originally no LOG exists. Should not be impacted by rename error.
  610. {
  611. std::shared_ptr<Logger> logger;
  612. ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
  613. ASSERT_TRUE(logger != nullptr);
  614. }
  615. // Now a LOG exists. Rename error should cause failure.
  616. {
  617. std::shared_ptr<Logger> logger;
  618. ASSERT_NOK(CreateLoggerFromOptions(kTestDir, options, &logger));
  619. ASSERT_TRUE(logger == nullptr);
  620. }
  621. }
  622. } // namespace ROCKSDB_NAMESPACE
  623. int main(int argc, char** argv) {
  624. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  625. ::testing::InitGoogleTest(&argc, argv);
  626. return RUN_ALL_TESTS();
  627. }