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