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).
6 #include "util/auto_roll_logger.h"
7 #include "util/mutexlock.h"
13 Status
AutoRollLogger::ResetLogger() {
14 TEST_SYNC_POINT("AutoRollLogger::ResetLogger:BeforeNewLogger");
15 status_
= env_
->NewLogger(log_fname_
, &logger_
);
16 TEST_SYNC_POINT("AutoRollLogger::ResetLogger:AfterNewLogger");
22 if (logger_
->GetLogFileSize() == Logger::kDoNotSupportGetLogFileSize
) {
23 status_
= Status::NotSupported(
24 "The underlying logger doesn't support GetLogFileSize()");
27 cached_now
= static_cast<uint64_t>(env_
->NowMicros() * 1e-6);
29 cached_now_access_count
= 0;
35 void AutoRollLogger::RollLogFile() {
36 // This function is called when log is rotating. Two rotations
37 // can happen quickly (NowMicro returns same value). To not overwrite
38 // previous log file we increment by one micro second and try again.
39 uint64_t now
= env_
->NowMicros();
40 std::string old_fname
;
42 old_fname
= OldInfoLogFileName(
43 dbname_
, now
, db_absolute_path_
, db_log_dir_
);
45 } while (env_
->FileExists(old_fname
).ok());
46 env_
->RenameFile(log_fname_
, old_fname
);
49 std::string
AutoRollLogger::ValistToString(const char* format
,
51 // Any log messages longer than 1024 will get truncated.
52 // The user is responsible for chopping longer messages into multi line log
53 static const int MAXBUFFERSIZE
= 1024;
54 char buffer
[MAXBUFFERSIZE
];
56 int count
= vsnprintf(buffer
, MAXBUFFERSIZE
, format
, args
);
63 void AutoRollLogger::LogInternal(const char* format
, ...) {
66 va_start(args
, format
);
67 logger_
->Logv(format
, args
);
71 void AutoRollLogger::Logv(const char* format
, va_list ap
) {
72 assert(GetStatus().ok());
74 std::shared_ptr
<Logger
> logger
;
77 if ((kLogFileTimeToRoll
> 0 && LogExpired()) ||
78 (kMaxLogFileSize
> 0 && logger_
->GetLogFileSize() >= kMaxLogFileSize
)) {
80 Status s
= ResetLogger();
82 // can't really log the error if creating a new LOG file failed
89 // pin down the current logger_ instance before releasing the mutex.
93 // Another thread could have put a new Logger instance into logger_ by now.
94 // However, since logger is still hanging on to the previous instance
95 // (reference count is not zero), we don't have to worry about it being
96 // deleted while we are accessing it.
97 // Note that logv itself is not mutex protected to allow maximum concurrency,
98 // as thread safety should have been handled by the underlying logger.
99 logger
->Logv(format
, ap
);
102 void AutoRollLogger::WriteHeaderInfo() {
104 for (auto& header
: headers_
) {
105 LogInternal("%s", header
.c_str());
109 void AutoRollLogger::LogHeader(const char* format
, va_list args
) {
110 // header message are to be retained in memory. Since we cannot make any
111 // assumptions about the data contained in va_list, we will retain them as
115 std::string data
= ValistToString(format
, tmp
);
118 MutexLock
l(&mutex_
);
119 headers_
.push_back(data
);
121 // Log the original message to the current log
122 logger_
->Logv(format
, args
);
125 bool AutoRollLogger::LogExpired() {
126 if (cached_now_access_count
>= call_NowMicros_every_N_records_
) {
127 cached_now
= static_cast<uint64_t>(env_
->NowMicros() * 1e-6);
128 cached_now_access_count
= 0;
131 ++cached_now_access_count
;
132 return cached_now
>= ctime_
+ kLogFileTimeToRoll
;
134 #endif // !ROCKSDB_LITE
136 Status
CreateLoggerFromOptions(const std::string
& dbname
,
137 const DBOptions
& options
,
138 std::shared_ptr
<Logger
>* logger
) {
139 if (options
.info_log
) {
140 *logger
= options
.info_log
;
144 Env
* env
= options
.env
;
145 std::string db_absolute_path
;
146 env
->GetAbsolutePath(dbname
, &db_absolute_path
);
148 InfoLogFileName(dbname
, db_absolute_path
, options
.db_log_dir
);
150 env
->CreateDirIfMissing(dbname
); // In case it does not exist
151 // Currently we only support roll by time-to-roll and log size
153 if (options
.log_file_time_to_roll
> 0 || options
.max_log_file_size
> 0) {
154 AutoRollLogger
* result
= new AutoRollLogger(
155 env
, dbname
, options
.db_log_dir
, options
.max_log_file_size
,
156 options
.log_file_time_to_roll
, options
.info_log_level
);
157 Status s
= result
->GetStatus();
161 logger
->reset(result
);
165 #endif // !ROCKSDB_LITE
166 // Open a log file in the same directory as the db
167 env
->RenameFile(fname
,
168 OldInfoLogFileName(dbname
, env
->NowMicros(), db_absolute_path
,
169 options
.db_log_dir
));
170 auto s
= env
->NewLogger(fname
, logger
);
171 if (logger
->get() != nullptr) {
172 (*logger
)->SetInfoLogLevel(options
.info_log_level
);
177 } // namespace rocksdb