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 #pragma once 7 8 #include <memory> 9 #include <sstream> 10 #include <string> 11 #include <chrono> 12 13 #include "logging/log_buffer.h" 14 #include "rocksdb/env.h" 15 16 namespace ROCKSDB_NAMESPACE { 17 18 class JSONWriter { 19 public: JSONWriter()20 JSONWriter() : state_(kExpectKey), first_element_(true), in_array_(false) { 21 stream_ << "{"; 22 } 23 AddKey(const std::string & key)24 void AddKey(const std::string& key) { 25 assert(state_ == kExpectKey); 26 if (!first_element_) { 27 stream_ << ", "; 28 } 29 stream_ << "\"" << key << "\": "; 30 state_ = kExpectValue; 31 first_element_ = false; 32 } 33 AddValue(const char * value)34 void AddValue(const char* value) { 35 assert(state_ == kExpectValue || state_ == kInArray); 36 if (state_ == kInArray && !first_element_) { 37 stream_ << ", "; 38 } 39 stream_ << "\"" << value << "\""; 40 if (state_ != kInArray) { 41 state_ = kExpectKey; 42 } 43 first_element_ = false; 44 } 45 46 template <typename T> AddValue(const T & value)47 void AddValue(const T& value) { 48 assert(state_ == kExpectValue || state_ == kInArray); 49 if (state_ == kInArray && !first_element_) { 50 stream_ << ", "; 51 } 52 stream_ << value; 53 if (state_ != kInArray) { 54 state_ = kExpectKey; 55 } 56 first_element_ = false; 57 } 58 StartArray()59 void StartArray() { 60 assert(state_ == kExpectValue); 61 state_ = kInArray; 62 in_array_ = true; 63 stream_ << "["; 64 first_element_ = true; 65 } 66 EndArray()67 void EndArray() { 68 assert(state_ == kInArray); 69 state_ = kExpectKey; 70 in_array_ = false; 71 stream_ << "]"; 72 first_element_ = false; 73 } 74 StartObject()75 void StartObject() { 76 assert(state_ == kExpectValue); 77 state_ = kExpectKey; 78 stream_ << "{"; 79 first_element_ = true; 80 } 81 EndObject()82 void EndObject() { 83 assert(state_ == kExpectKey); 84 stream_ << "}"; 85 first_element_ = false; 86 } 87 StartArrayedObject()88 void StartArrayedObject() { 89 assert(state_ == kInArray && in_array_); 90 state_ = kExpectValue; 91 if (!first_element_) { 92 stream_ << ", "; 93 } 94 StartObject(); 95 } 96 EndArrayedObject()97 void EndArrayedObject() { 98 assert(in_array_); 99 EndObject(); 100 state_ = kInArray; 101 } 102 Get()103 std::string Get() const { return stream_.str(); } 104 105 JSONWriter& operator<<(const char* val) { 106 if (state_ == kExpectKey) { 107 AddKey(val); 108 } else { 109 AddValue(val); 110 } 111 return *this; 112 } 113 114 JSONWriter& operator<<(const std::string& val) { 115 return *this << val.c_str(); 116 } 117 118 template <typename T> 119 JSONWriter& operator<<(const T& val) { 120 assert(state_ != kExpectKey); 121 AddValue(val); 122 return *this; 123 } 124 125 private: 126 enum JSONWriterState { 127 kExpectKey, 128 kExpectValue, 129 kInArray, 130 kInArrayedObject, 131 }; 132 JSONWriterState state_; 133 bool first_element_; 134 bool in_array_; 135 std::ostringstream stream_; 136 }; 137 138 class EventLoggerStream { 139 public: 140 template <typename T> 141 EventLoggerStream& operator<<(const T& val) { 142 MakeStream(); 143 *json_writer_ << val; 144 return *this; 145 } 146 StartArray()147 void StartArray() { json_writer_->StartArray(); } EndArray()148 void EndArray() { json_writer_->EndArray(); } StartObject()149 void StartObject() { json_writer_->StartObject(); } EndObject()150 void EndObject() { json_writer_->EndObject(); } 151 152 ~EventLoggerStream(); 153 154 private: MakeStream()155 void MakeStream() { 156 if (!json_writer_) { 157 json_writer_ = new JSONWriter(); 158 *this << "time_micros" 159 << std::chrono::duration_cast<std::chrono::microseconds>( 160 std::chrono::system_clock::now().time_since_epoch()).count(); 161 } 162 } 163 friend class EventLogger; 164 explicit EventLoggerStream(Logger* logger); 165 explicit EventLoggerStream(LogBuffer* log_buffer, const size_t max_log_size); 166 // exactly one is non-nullptr 167 Logger* const logger_; 168 LogBuffer* const log_buffer_; 169 const size_t max_log_size_; // used only for log_buffer_ 170 // ownership 171 JSONWriter* json_writer_; 172 }; 173 174 // here is an example of the output that will show up in the LOG: 175 // 2015/01/15-14:13:25.788019 1105ef000 EVENT_LOG_v1 {"time_micros": 176 // 1421360005788015, "event": "table_file_creation", "file_number": 12, 177 // "file_size": 1909699} 178 class EventLogger { 179 public: Prefix()180 static const char* Prefix() { 181 return "EVENT_LOG_v1"; 182 } 183 EventLogger(Logger * logger)184 explicit EventLogger(Logger* logger) : logger_(logger) {} Log()185 EventLoggerStream Log() { return EventLoggerStream(logger_); } LogToBuffer(LogBuffer * log_buffer)186 EventLoggerStream LogToBuffer(LogBuffer* log_buffer) { 187 return EventLoggerStream(log_buffer, LogBuffer::kDefaultMaxLogSize); 188 } LogToBuffer(LogBuffer * log_buffer,const size_t max_log_size)189 EventLoggerStream LogToBuffer(LogBuffer* log_buffer, 190 const size_t max_log_size) { 191 return EventLoggerStream(log_buffer, max_log_size); 192 } 193 void Log(const JSONWriter& jwriter); 194 static void Log(Logger* logger, const JSONWriter& jwriter); 195 static void LogToBuffer( 196 LogBuffer* log_buffer, const JSONWriter& jwriter, 197 const size_t max_log_size = LogBuffer::kDefaultMaxLogSize); 198 199 private: 200 Logger* logger_; 201 }; 202 203 } // namespace ROCKSDB_NAMESPACE 204