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/log_buffer.h"
7
8 #include "port/sys_time.h"
9 #include "port/port.h"
10
11 namespace ROCKSDB_NAMESPACE {
12
LogBuffer(const InfoLogLevel log_level,Logger * info_log)13 LogBuffer::LogBuffer(const InfoLogLevel log_level,
14 Logger*info_log)
15 : log_level_(log_level), info_log_(info_log) {}
16
AddLogToBuffer(size_t max_log_size,const char * format,va_list ap)17 void LogBuffer::AddLogToBuffer(size_t max_log_size, const char* format,
18 va_list ap) {
19 if (!info_log_ || log_level_ < info_log_->GetInfoLogLevel()) {
20 // Skip the level because of its level.
21 return;
22 }
23
24 char* alloc_mem = arena_.AllocateAligned(max_log_size);
25 BufferedLog* buffered_log = new (alloc_mem) BufferedLog();
26 char* p = buffered_log->message;
27 char* limit = alloc_mem + max_log_size - 1;
28
29 // store the time
30 gettimeofday(&(buffered_log->now_tv), nullptr);
31
32 // Print the message
33 if (p < limit) {
34 va_list backup_ap;
35 va_copy(backup_ap, ap);
36 auto n = vsnprintf(p, limit - p, format, backup_ap);
37 #ifndef OS_WIN
38 // MS reports -1 when the buffer is too short
39 assert(n >= 0);
40 #endif
41 if (n > 0) {
42 p += n;
43 } else {
44 p = limit;
45 }
46 va_end(backup_ap);
47 }
48
49 if (p > limit) {
50 p = limit;
51 }
52
53 // Add '\0' to the end
54 *p = '\0';
55
56 logs_.push_back(buffered_log);
57 }
58
FlushBufferToLog()59 void LogBuffer::FlushBufferToLog() {
60 for (BufferedLog* log : logs_) {
61 const time_t seconds = log->now_tv.tv_sec;
62 struct tm t;
63 if (localtime_r(&seconds, &t) != nullptr) {
64 Log(log_level_, info_log_,
65 "(Original Log Time %04d/%02d/%02d-%02d:%02d:%02d.%06d) %s",
66 t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min,
67 t.tm_sec, static_cast<int>(log->now_tv.tv_usec), log->message);
68 }
69 }
70 logs_.clear();
71 }
72
LogToBuffer(LogBuffer * log_buffer,size_t max_log_size,const char * format,...)73 void LogToBuffer(LogBuffer* log_buffer, size_t max_log_size, const char* format,
74 ...) {
75 if (log_buffer != nullptr) {
76 va_list ap;
77 va_start(ap, format);
78 log_buffer->AddLogToBuffer(max_log_size, format, ap);
79 va_end(ap);
80 }
81 }
82
LogToBuffer(LogBuffer * log_buffer,const char * format,...)83 void LogToBuffer(LogBuffer* log_buffer, const char* format, ...) {
84 if (log_buffer != nullptr) {
85 va_list ap;
86 va_start(ap, format);
87 log_buffer->AddLogToBuffer(LogBuffer::kDefaultMaxLogSize, format, ap);
88 va_end(ap);
89 }
90 }
91
92 } // namespace ROCKSDB_NAMESPACE
93