| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- //
- #ifndef ROCKSDB_LITE
- #include "logging/auto_roll_logger.h"
- #include <errno.h>
- #include <sys/stat.h>
- #include <algorithm>
- #include <cmath>
- #include <fstream>
- #include <iostream>
- #include <iterator>
- #include <string>
- #include <thread>
- #include <vector>
- #include "logging/logging.h"
- #include "port/port.h"
- #include "rocksdb/db.h"
- #include "test_util/sync_point.h"
- #include "test_util/testharness.h"
- #include "test_util/testutil.h"
- namespace ROCKSDB_NAMESPACE {
- namespace {
- class NoSleepEnv : public EnvWrapper {
- public:
- NoSleepEnv(Env* base) : EnvWrapper(base) {}
- void SleepForMicroseconds(int micros) override {
- fake_time_ += static_cast<uint64_t>(micros);
- }
- uint64_t NowNanos() override { return fake_time_ * 1000; }
- uint64_t NowMicros() override { return fake_time_; }
- private:
- uint64_t fake_time_ = 6666666666;
- };
- } // namespace
- // In this test we only want to Log some simple log message with
- // no format. LogMessage() provides such a simple interface and
- // avoids the [format-security] warning which occurs when you
- // call ROCKS_LOG_INFO(logger, log_message) directly.
- namespace {
- void LogMessage(Logger* logger, const char* message) {
- ROCKS_LOG_INFO(logger, "%s", message);
- }
- void LogMessage(const InfoLogLevel log_level, Logger* logger,
- const char* message) {
- Log(log_level, logger, "%s", message);
- }
- } // namespace
- class AutoRollLoggerTest : public testing::Test {
- public:
- static void InitTestDb() {
- #ifdef OS_WIN
- // Replace all slashes in the path so windows CompSpec does not
- // become confused
- std::string testDir(kTestDir);
- std::replace_if(testDir.begin(), testDir.end(),
- [](char ch) { return ch == '/'; }, '\\');
- std::string deleteCmd = "if exist " + testDir + " rd /s /q " + testDir;
- #else
- std::string deleteCmd = "rm -rf " + kTestDir;
- #endif
- ASSERT_TRUE(system(deleteCmd.c_str()) == 0);
- Env::Default()->CreateDir(kTestDir);
- }
- void RollLogFileBySizeTest(AutoRollLogger* logger, size_t log_max_size,
- const std::string& log_message);
- void RollLogFileByTimeTest(Env*, AutoRollLogger* logger, size_t time,
- const std::string& log_message);
- // return list of files under kTestDir that contains "LOG"
- std::vector<std::string> GetLogFiles() {
- std::vector<std::string> ret;
- std::vector<std::string> files;
- Status s = default_env->GetChildren(kTestDir, &files);
- // Should call ASSERT_OK() here but it doesn't compile. It's not
- // worth the time figuring out why.
- EXPECT_TRUE(s.ok());
- for (const auto& f : files) {
- if (f.find("LOG") != std::string::npos) {
- ret.push_back(f);
- }
- }
- return ret;
- }
- // Delete all log files under kTestDir
- void CleanupLogFiles() {
- for (const std::string& f : GetLogFiles()) {
- ASSERT_OK(default_env->DeleteFile(kTestDir + "/" + f));
- }
- }
- void RollNTimesBySize(Logger* auto_roll_logger, size_t file_num,
- size_t max_log_file_size) {
- // Roll the log 4 times, and it will trim to 3 files.
- std::string dummy_large_string;
- dummy_large_string.assign(max_log_file_size, '=');
- auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
- for (size_t i = 0; i < file_num + 1; i++) {
- // Log enough bytes to trigger at least one roll.
- LogMessage(auto_roll_logger, dummy_large_string.c_str());
- LogMessage(auto_roll_logger, "");
- }
- }
- static const std::string kSampleMessage;
- static const std::string kTestDir;
- static const std::string kLogFile;
- static Env* default_env;
- };
- const std::string AutoRollLoggerTest::kSampleMessage(
- "this is the message to be written to the log file!!");
- const std::string AutoRollLoggerTest::kTestDir(
- test::PerThreadDBPath("db_log_test"));
- const std::string AutoRollLoggerTest::kLogFile(
- test::PerThreadDBPath("db_log_test") + "/LOG");
- Env* AutoRollLoggerTest::default_env = Env::Default();
- void AutoRollLoggerTest::RollLogFileBySizeTest(AutoRollLogger* logger,
- size_t log_max_size,
- const std::string& log_message) {
- logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
- ASSERT_EQ(InfoLogLevel::INFO_LEVEL, logger->GetInfoLogLevel());
- ASSERT_EQ(InfoLogLevel::INFO_LEVEL,
- logger->TEST_inner_logger()->GetInfoLogLevel());
- // measure the size of each message, which is supposed
- // to be equal or greater than log_message.size()
- LogMessage(logger, log_message.c_str());
- size_t message_size = logger->GetLogFileSize();
- size_t current_log_size = message_size;
- // Test the cases when the log file will not be rolled.
- while (current_log_size + message_size < log_max_size) {
- LogMessage(logger, log_message.c_str());
- current_log_size += message_size;
- ASSERT_EQ(current_log_size, logger->GetLogFileSize());
- }
- // Now the log file will be rolled
- LogMessage(logger, log_message.c_str());
- // Since rotation is checked before actual logging, we need to
- // trigger the rotation by logging another message.
- LogMessage(logger, log_message.c_str());
- ASSERT_TRUE(message_size == logger->GetLogFileSize());
- }
- void AutoRollLoggerTest::RollLogFileByTimeTest(Env* env, AutoRollLogger* logger,
- size_t time,
- const std::string& log_message) {
- uint64_t expected_ctime;
- uint64_t actual_ctime;
- uint64_t total_log_size;
- EXPECT_OK(env->GetFileSize(kLogFile, &total_log_size));
- expected_ctime = logger->TEST_ctime();
- logger->SetCallNowMicrosEveryNRecords(0);
- // -- Write to the log for several times, which is supposed
- // to be finished before time.
- for (int i = 0; i < 10; ++i) {
- env->SleepForMicroseconds(50000);
- LogMessage(logger, log_message.c_str());
- EXPECT_OK(logger->GetStatus());
- // Make sure we always write to the same log file (by
- // checking the create time);
- actual_ctime = logger->TEST_ctime();
- // Also make sure the log size is increasing.
- EXPECT_EQ(expected_ctime, actual_ctime);
- EXPECT_GT(logger->GetLogFileSize(), total_log_size);
- total_log_size = logger->GetLogFileSize();
- }
- // -- Make the log file expire
- env->SleepForMicroseconds(static_cast<int>(time * 1000000));
- LogMessage(logger, log_message.c_str());
- // At this time, the new log file should be created.
- actual_ctime = logger->TEST_ctime();
- EXPECT_LT(expected_ctime, actual_ctime);
- EXPECT_LT(logger->GetLogFileSize(), total_log_size);
- }
- TEST_F(AutoRollLoggerTest, RollLogFileBySize) {
- InitTestDb();
- size_t log_max_size = 1024 * 5;
- size_t keep_log_file_num = 10;
- AutoRollLogger logger(Env::Default(), kTestDir, "", log_max_size, 0,
- keep_log_file_num);
- RollLogFileBySizeTest(&logger, log_max_size,
- kSampleMessage + ":RollLogFileBySize");
- }
- TEST_F(AutoRollLoggerTest, RollLogFileByTime) {
- NoSleepEnv nse(Env::Default());
- size_t time = 2;
- size_t log_size = 1024 * 5;
- size_t keep_log_file_num = 10;
- InitTestDb();
- // -- Test the existence of file during the server restart.
- ASSERT_EQ(Status::NotFound(), default_env->FileExists(kLogFile));
- AutoRollLogger logger(&nse, kTestDir, "", log_size, time, keep_log_file_num);
- ASSERT_OK(default_env->FileExists(kLogFile));
- RollLogFileByTimeTest(&nse, &logger, time,
- kSampleMessage + ":RollLogFileByTime");
- }
- TEST_F(AutoRollLoggerTest, SetInfoLogLevel) {
- InitTestDb();
- Options options;
- options.info_log_level = InfoLogLevel::FATAL_LEVEL;
- options.max_log_file_size = 1024;
- std::shared_ptr<Logger> logger;
- ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
- auto* auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());
- ASSERT_NE(nullptr, auto_roll_logger);
- ASSERT_EQ(InfoLogLevel::FATAL_LEVEL, auto_roll_logger->GetInfoLogLevel());
- ASSERT_EQ(InfoLogLevel::FATAL_LEVEL,
- auto_roll_logger->TEST_inner_logger()->GetInfoLogLevel());
- auto_roll_logger->SetInfoLogLevel(InfoLogLevel::DEBUG_LEVEL);
- ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL, auto_roll_logger->GetInfoLogLevel());
- ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL, logger->GetInfoLogLevel());
- ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL,
- auto_roll_logger->TEST_inner_logger()->GetInfoLogLevel());
- }
- TEST_F(AutoRollLoggerTest, OpenLogFilesMultipleTimesWithOptionLog_max_size) {
- // If only 'log_max_size' options is specified, then every time
- // when rocksdb is restarted, a new empty log file will be created.
- InitTestDb();
- // WORKAROUND:
- // avoid complier's complaint of "comparison between signed
- // and unsigned integer expressions" because literal 0 is
- // treated as "singed".
- size_t kZero = 0;
- size_t log_size = 1024;
- size_t keep_log_file_num = 10;
- AutoRollLogger* logger = new AutoRollLogger(Env::Default(), kTestDir, "",
- log_size, 0, keep_log_file_num);
- LogMessage(logger, kSampleMessage.c_str());
- ASSERT_GT(logger->GetLogFileSize(), kZero);
- delete logger;
- // reopens the log file and an empty log file will be created.
- logger = new AutoRollLogger(Env::Default(), kTestDir, "", log_size, 0, 10);
- ASSERT_EQ(logger->GetLogFileSize(), kZero);
- delete logger;
- }
- TEST_F(AutoRollLoggerTest, CompositeRollByTimeAndSizeLogger) {
- size_t time = 2, log_max_size = 1024 * 5;
- size_t keep_log_file_num = 10;
- InitTestDb();
- NoSleepEnv nse(Env::Default());
- AutoRollLogger logger(&nse, kTestDir, "", log_max_size, time,
- keep_log_file_num);
- // Test the ability to roll by size
- RollLogFileBySizeTest(&logger, log_max_size,
- kSampleMessage + ":CompositeRollByTimeAndSizeLogger");
- // Test the ability to roll by Time
- RollLogFileByTimeTest(&nse, &logger, time,
- kSampleMessage + ":CompositeRollByTimeAndSizeLogger");
- }
- #ifndef OS_WIN
- // TODO: does not build for Windows because of PosixLogger use below. Need to
- // port
- TEST_F(AutoRollLoggerTest, CreateLoggerFromOptions) {
- DBOptions options;
- NoSleepEnv nse(Env::Default());
- std::shared_ptr<Logger> logger;
- // Normal logger
- ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
- ASSERT_TRUE(dynamic_cast<PosixLogger*>(logger.get()));
- // Only roll by size
- InitTestDb();
- options.max_log_file_size = 1024;
- ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
- AutoRollLogger* auto_roll_logger =
- dynamic_cast<AutoRollLogger*>(logger.get());
- ASSERT_TRUE(auto_roll_logger);
- RollLogFileBySizeTest(
- auto_roll_logger, options.max_log_file_size,
- kSampleMessage + ":CreateLoggerFromOptions - size");
- // Only roll by Time
- options.env = &nse;
- InitTestDb();
- options.max_log_file_size = 0;
- options.log_file_time_to_roll = 2;
- ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
- auto_roll_logger =
- dynamic_cast<AutoRollLogger*>(logger.get());
- RollLogFileByTimeTest(&nse, auto_roll_logger, options.log_file_time_to_roll,
- kSampleMessage + ":CreateLoggerFromOptions - time");
- // roll by both Time and size
- InitTestDb();
- options.max_log_file_size = 1024 * 5;
- options.log_file_time_to_roll = 2;
- ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
- auto_roll_logger =
- dynamic_cast<AutoRollLogger*>(logger.get());
- RollLogFileBySizeTest(auto_roll_logger, options.max_log_file_size,
- kSampleMessage + ":CreateLoggerFromOptions - both");
- RollLogFileByTimeTest(&nse, auto_roll_logger, options.log_file_time_to_roll,
- kSampleMessage + ":CreateLoggerFromOptions - both");
- // Set keep_log_file_num
- {
- const size_t kFileNum = 3;
- InitTestDb();
- options.max_log_file_size = 512;
- options.log_file_time_to_roll = 2;
- options.keep_log_file_num = kFileNum;
- ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
- auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());
- // Roll the log 4 times, and it will trim to 3 files.
- std::string dummy_large_string;
- dummy_large_string.assign(options.max_log_file_size, '=');
- auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
- for (size_t i = 0; i < kFileNum + 1; i++) {
- // Log enough bytes to trigger at least one roll.
- LogMessage(auto_roll_logger, dummy_large_string.c_str());
- LogMessage(auto_roll_logger, "");
- }
- std::vector<std::string> files = GetLogFiles();
- ASSERT_EQ(kFileNum, files.size());
- CleanupLogFiles();
- }
- // Set keep_log_file_num and dbname is different from
- // db_log_dir.
- {
- const size_t kFileNum = 3;
- InitTestDb();
- options.max_log_file_size = 512;
- options.log_file_time_to_roll = 2;
- options.keep_log_file_num = kFileNum;
- options.db_log_dir = kTestDir;
- ASSERT_OK(CreateLoggerFromOptions("/dummy/db/name", options, &logger));
- auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());
- // Roll the log 4 times, and it will trim to 3 files.
- std::string dummy_large_string;
- dummy_large_string.assign(options.max_log_file_size, '=');
- auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
- for (size_t i = 0; i < kFileNum + 1; i++) {
- // Log enough bytes to trigger at least one roll.
- LogMessage(auto_roll_logger, dummy_large_string.c_str());
- LogMessage(auto_roll_logger, "");
- }
- std::vector<std::string> files = GetLogFiles();
- ASSERT_EQ(kFileNum, files.size());
- for (const auto& f : files) {
- ASSERT_TRUE(f.find("dummy") != std::string::npos);
- }
- // Cleaning up those files.
- CleanupLogFiles();
- }
- }
- TEST_F(AutoRollLoggerTest, AutoDeleting) {
- for (int attempt = 0; attempt < 2; attempt++) {
- // In the first attemp, db_log_dir is not set, while in the
- // second it is set.
- std::string dbname = (attempt == 0) ? kTestDir : "/test/dummy/dir";
- std::string db_log_dir = (attempt == 0) ? "" : kTestDir;
- InitTestDb();
- const size_t kMaxFileSize = 512;
- {
- size_t log_num = 8;
- AutoRollLogger logger(Env::Default(), dbname, db_log_dir, kMaxFileSize, 0,
- log_num);
- RollNTimesBySize(&logger, log_num, kMaxFileSize);
- ASSERT_EQ(log_num, GetLogFiles().size());
- }
- // Shrink number of files
- {
- size_t log_num = 5;
- AutoRollLogger logger(Env::Default(), dbname, db_log_dir, kMaxFileSize, 0,
- log_num);
- ASSERT_EQ(log_num, GetLogFiles().size());
- RollNTimesBySize(&logger, 3, kMaxFileSize);
- ASSERT_EQ(log_num, GetLogFiles().size());
- }
- // Increase number of files again.
- {
- size_t log_num = 7;
- AutoRollLogger logger(Env::Default(), dbname, db_log_dir, kMaxFileSize, 0,
- log_num);
- ASSERT_EQ(6, GetLogFiles().size());
- RollNTimesBySize(&logger, 3, kMaxFileSize);
- ASSERT_EQ(log_num, GetLogFiles().size());
- }
- CleanupLogFiles();
- }
- }
- TEST_F(AutoRollLoggerTest, LogFlushWhileRolling) {
- DBOptions options;
- std::shared_ptr<Logger> logger;
- InitTestDb();
- options.max_log_file_size = 1024 * 5;
- ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
- AutoRollLogger* auto_roll_logger =
- dynamic_cast<AutoRollLogger*>(logger.get());
- ASSERT_TRUE(auto_roll_logger);
- ROCKSDB_NAMESPACE::port::Thread flush_thread;
- // Notes:
- // (1) Need to pin the old logger before beginning the roll, as rolling grabs
- // the mutex, which would prevent us from accessing the old logger. This
- // also marks flush_thread with AutoRollLogger::Flush:PinnedLogger.
- // (2) Need to reset logger during PosixLogger::Flush() to exercise a race
- // condition case, which is executing the flush with the pinned (old)
- // logger after auto-roll logger has cut over to a new logger.
- // (3) PosixLogger::Flush() happens in both threads but its SyncPoints only
- // are enabled in flush_thread (the one pinning the old logger).
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependencyAndMarkers(
- {{"AutoRollLogger::Flush:PinnedLogger",
- "AutoRollLoggerTest::LogFlushWhileRolling:PreRollAndPostThreadInit"},
- {"PosixLogger::Flush:Begin1",
- "AutoRollLogger::ResetLogger:BeforeNewLogger"},
- {"AutoRollLogger::ResetLogger:AfterNewLogger",
- "PosixLogger::Flush:Begin2"}},
- {{"AutoRollLogger::Flush:PinnedLogger", "PosixLogger::Flush:Begin1"},
- {"AutoRollLogger::Flush:PinnedLogger", "PosixLogger::Flush:Begin2"}});
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
- flush_thread = port::Thread([&]() { auto_roll_logger->Flush(); });
- TEST_SYNC_POINT(
- "AutoRollLoggerTest::LogFlushWhileRolling:PreRollAndPostThreadInit");
- RollLogFileBySizeTest(auto_roll_logger, options.max_log_file_size,
- kSampleMessage + ":LogFlushWhileRolling");
- flush_thread.join();
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
- }
- #endif // OS_WIN
- TEST_F(AutoRollLoggerTest, InfoLogLevel) {
- InitTestDb();
- size_t log_size = 8192;
- size_t log_lines = 0;
- // an extra-scope to force the AutoRollLogger to flush the log file when it
- // becomes out of scope.
- {
- AutoRollLogger logger(Env::Default(), kTestDir, "", log_size, 0, 10);
- for (int log_level = InfoLogLevel::HEADER_LEVEL;
- log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {
- logger.SetInfoLogLevel((InfoLogLevel)log_level);
- for (int log_type = InfoLogLevel::DEBUG_LEVEL;
- log_type <= InfoLogLevel::HEADER_LEVEL; log_type++) {
- // log messages with log level smaller than log_level will not be
- // logged.
- LogMessage((InfoLogLevel)log_type, &logger, kSampleMessage.c_str());
- }
- log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;
- }
- for (int log_level = InfoLogLevel::HEADER_LEVEL;
- log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {
- logger.SetInfoLogLevel((InfoLogLevel)log_level);
- // again, messages with level smaller than log_level will not be logged.
- ROCKS_LOG_HEADER(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_DEBUG(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_INFO(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_WARN(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_ERROR(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_FATAL(&logger, "%s", kSampleMessage.c_str());
- log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;
- }
- }
- std::ifstream inFile(AutoRollLoggerTest::kLogFile.c_str());
- size_t lines = std::count(std::istreambuf_iterator<char>(inFile),
- std::istreambuf_iterator<char>(), '\n');
- ASSERT_EQ(log_lines, lines);
- inFile.close();
- }
- TEST_F(AutoRollLoggerTest, Close) {
- InitTestDb();
- size_t log_size = 8192;
- size_t log_lines = 0;
- AutoRollLogger logger(Env::Default(), kTestDir, "", log_size, 0, 10);
- for (int log_level = InfoLogLevel::HEADER_LEVEL;
- log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {
- logger.SetInfoLogLevel((InfoLogLevel)log_level);
- for (int log_type = InfoLogLevel::DEBUG_LEVEL;
- log_type <= InfoLogLevel::HEADER_LEVEL; log_type++) {
- // log messages with log level smaller than log_level will not be
- // logged.
- LogMessage((InfoLogLevel)log_type, &logger, kSampleMessage.c_str());
- }
- log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;
- }
- for (int log_level = InfoLogLevel::HEADER_LEVEL;
- log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {
- logger.SetInfoLogLevel((InfoLogLevel)log_level);
- // again, messages with level smaller than log_level will not be logged.
- ROCKS_LOG_HEADER(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_DEBUG(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_INFO(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_WARN(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_ERROR(&logger, "%s", kSampleMessage.c_str());
- ROCKS_LOG_FATAL(&logger, "%s", kSampleMessage.c_str());
- log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;
- }
- ASSERT_EQ(logger.Close(), Status::OK());
- std::ifstream inFile(AutoRollLoggerTest::kLogFile.c_str());
- size_t lines = std::count(std::istreambuf_iterator<char>(inFile),
- std::istreambuf_iterator<char>(), '\n');
- ASSERT_EQ(log_lines, lines);
- inFile.close();
- }
- // Test the logger Header function for roll over logs
- // We expect the new logs creates as roll over to carry the headers specified
- static std::vector<std::string> GetOldFileNames(const std::string& path) {
- std::vector<std::string> ret;
- const std::string dirname = path.substr(/*start=*/0, path.find_last_of("/"));
- const std::string fname = path.substr(path.find_last_of("/") + 1);
- std::vector<std::string> children;
- Env::Default()->GetChildren(dirname, &children);
- // We know that the old log files are named [path]<something>
- // Return all entities that match the pattern
- for (auto& child : children) {
- if (fname != child && child.find(fname) == 0) {
- ret.push_back(dirname + "/" + child);
- }
- }
- return ret;
- }
- TEST_F(AutoRollLoggerTest, LogHeaderTest) {
- static const size_t MAX_HEADERS = 10;
- static const size_t LOG_MAX_SIZE = 1024 * 5;
- static const std::string HEADER_STR = "Log header line";
- // test_num == 0 -> standard call to Header()
- // test_num == 1 -> call to Log() with InfoLogLevel::HEADER_LEVEL
- for (int test_num = 0; test_num < 2; test_num++) {
- InitTestDb();
- AutoRollLogger logger(Env::Default(), kTestDir, /*db_log_dir=*/"",
- LOG_MAX_SIZE, /*log_file_time_to_roll=*/0,
- /*keep_log_file_num=*/10);
- if (test_num == 0) {
- // Log some headers explicitly using Header()
- for (size_t i = 0; i < MAX_HEADERS; i++) {
- Header(&logger, "%s %" ROCKSDB_PRIszt, HEADER_STR.c_str(), i);
- }
- } else if (test_num == 1) {
- // HEADER_LEVEL should make this behave like calling Header()
- for (size_t i = 0; i < MAX_HEADERS; i++) {
- ROCKS_LOG_HEADER(&logger, "%s %" ROCKSDB_PRIszt, HEADER_STR.c_str(), i);
- }
- }
- const std::string newfname = logger.TEST_log_fname();
- // Log enough data to cause a roll over
- int i = 0;
- for (size_t iter = 0; iter < 2; iter++) {
- while (logger.GetLogFileSize() < LOG_MAX_SIZE) {
- Info(&logger, (kSampleMessage + ":LogHeaderTest line %d").c_str(), i);
- ++i;
- }
- Info(&logger, "Rollover");
- }
- // Flush the log for the latest file
- LogFlush(&logger);
- const auto oldfiles = GetOldFileNames(newfname);
- ASSERT_EQ(oldfiles.size(), (size_t) 2);
- for (auto& oldfname : oldfiles) {
- // verify that the files rolled over
- ASSERT_NE(oldfname, newfname);
- // verify that the old log contains all the header logs
- ASSERT_EQ(test::GetLinesCount(oldfname, HEADER_STR), MAX_HEADERS);
- }
- }
- }
- TEST_F(AutoRollLoggerTest, LogFileExistence) {
- ROCKSDB_NAMESPACE::DB* db;
- ROCKSDB_NAMESPACE::Options options;
- #ifdef OS_WIN
- // Replace all slashes in the path so windows CompSpec does not
- // become confused
- std::string testDir(kTestDir);
- std::replace_if(testDir.begin(), testDir.end(),
- [](char ch) { return ch == '/'; }, '\\');
- std::string deleteCmd = "if exist " + testDir + " rd /s /q " + testDir;
- #else
- std::string deleteCmd = "rm -rf " + kTestDir;
- #endif
- ASSERT_EQ(system(deleteCmd.c_str()), 0);
- options.max_log_file_size = 100 * 1024 * 1024;
- options.create_if_missing = true;
- ASSERT_OK(ROCKSDB_NAMESPACE::DB::Open(options, kTestDir, &db));
- ASSERT_OK(default_env->FileExists(kLogFile));
- delete db;
- }
- TEST_F(AutoRollLoggerTest, FileCreateFailure) {
- Options options;
- options.max_log_file_size = 100 * 1024 * 1024;
- options.db_log_dir = "/a/dir/does/not/exist/at/all";
- std::shared_ptr<Logger> logger;
- ASSERT_NOK(CreateLoggerFromOptions("", options, &logger));
- ASSERT_TRUE(!logger);
- }
- } // namespace ROCKSDB_NAMESPACE
- int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
- }
- #else
- #include <stdio.h>
- int main(int /*argc*/, char** /*argv*/) {
- fprintf(stderr,
- "SKIPPED as AutoRollLogger is not supported in ROCKSDB_LITE\n");
- return 0;
- }
- #endif // !ROCKSDB_LITE
|