1*9507f98cSAndroid Build Coastguard Worker // Copyright (c) 2011 The LevelDB Authors. All rights reserved. 2*9507f98cSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*9507f98cSAndroid Build Coastguard Worker // found in the LICENSE file. See the AUTHORS file for names of contributors. 4*9507f98cSAndroid Build Coastguard Worker // 5*9507f98cSAndroid Build Coastguard Worker // Logger implementation that can be shared by all environments 6*9507f98cSAndroid Build Coastguard Worker // where enough posix functionality is available. 7*9507f98cSAndroid Build Coastguard Worker 8*9507f98cSAndroid Build Coastguard Worker #ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ 9*9507f98cSAndroid Build Coastguard Worker #define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ 10*9507f98cSAndroid Build Coastguard Worker 11*9507f98cSAndroid Build Coastguard Worker #include <sys/time.h> 12*9507f98cSAndroid Build Coastguard Worker 13*9507f98cSAndroid Build Coastguard Worker #include <cassert> 14*9507f98cSAndroid Build Coastguard Worker #include <cstdarg> 15*9507f98cSAndroid Build Coastguard Worker #include <cstdio> 16*9507f98cSAndroid Build Coastguard Worker #include <ctime> 17*9507f98cSAndroid Build Coastguard Worker #include <sstream> 18*9507f98cSAndroid Build Coastguard Worker #include <thread> 19*9507f98cSAndroid Build Coastguard Worker 20*9507f98cSAndroid Build Coastguard Worker #include "leveldb/env.h" 21*9507f98cSAndroid Build Coastguard Worker 22*9507f98cSAndroid Build Coastguard Worker namespace leveldb { 23*9507f98cSAndroid Build Coastguard Worker 24*9507f98cSAndroid Build Coastguard Worker class PosixLogger final : public Logger { 25*9507f98cSAndroid Build Coastguard Worker public: 26*9507f98cSAndroid Build Coastguard Worker // Creates a logger that writes to the given file. 27*9507f98cSAndroid Build Coastguard Worker // 28*9507f98cSAndroid Build Coastguard Worker // The PosixLogger instance takes ownership of the file handle. PosixLogger(std::FILE * fp)29*9507f98cSAndroid Build Coastguard Worker explicit PosixLogger(std::FILE* fp) : fp_(fp) { assert(fp != nullptr); } 30*9507f98cSAndroid Build Coastguard Worker ~PosixLogger()31*9507f98cSAndroid Build Coastguard Worker ~PosixLogger() override { std::fclose(fp_); } 32*9507f98cSAndroid Build Coastguard Worker Logv(const char * format,std::va_list arguments)33*9507f98cSAndroid Build Coastguard Worker void Logv(const char* format, std::va_list arguments) override { 34*9507f98cSAndroid Build Coastguard Worker // Record the time as close to the Logv() call as possible. 35*9507f98cSAndroid Build Coastguard Worker struct ::timeval now_timeval; 36*9507f98cSAndroid Build Coastguard Worker ::gettimeofday(&now_timeval, nullptr); 37*9507f98cSAndroid Build Coastguard Worker const std::time_t now_seconds = now_timeval.tv_sec; 38*9507f98cSAndroid Build Coastguard Worker struct std::tm now_components; 39*9507f98cSAndroid Build Coastguard Worker ::localtime_r(&now_seconds, &now_components); 40*9507f98cSAndroid Build Coastguard Worker 41*9507f98cSAndroid Build Coastguard Worker // Record the thread ID. 42*9507f98cSAndroid Build Coastguard Worker constexpr const int kMaxThreadIdSize = 32; 43*9507f98cSAndroid Build Coastguard Worker std::ostringstream thread_stream; 44*9507f98cSAndroid Build Coastguard Worker thread_stream << std::this_thread::get_id(); 45*9507f98cSAndroid Build Coastguard Worker std::string thread_id = thread_stream.str(); 46*9507f98cSAndroid Build Coastguard Worker if (thread_id.size() > kMaxThreadIdSize) { 47*9507f98cSAndroid Build Coastguard Worker thread_id.resize(kMaxThreadIdSize); 48*9507f98cSAndroid Build Coastguard Worker } 49*9507f98cSAndroid Build Coastguard Worker 50*9507f98cSAndroid Build Coastguard Worker // We first attempt to print into a stack-allocated buffer. If this attempt 51*9507f98cSAndroid Build Coastguard Worker // fails, we make a second attempt with a dynamically allocated buffer. 52*9507f98cSAndroid Build Coastguard Worker constexpr const int kStackBufferSize = 512; 53*9507f98cSAndroid Build Coastguard Worker char stack_buffer[kStackBufferSize]; 54*9507f98cSAndroid Build Coastguard Worker static_assert(sizeof(stack_buffer) == static_cast<size_t>(kStackBufferSize), 55*9507f98cSAndroid Build Coastguard Worker "sizeof(char) is expected to be 1 in C++"); 56*9507f98cSAndroid Build Coastguard Worker 57*9507f98cSAndroid Build Coastguard Worker int dynamic_buffer_size = 0; // Computed in the first iteration. 58*9507f98cSAndroid Build Coastguard Worker for (int iteration = 0; iteration < 2; ++iteration) { 59*9507f98cSAndroid Build Coastguard Worker const int buffer_size = 60*9507f98cSAndroid Build Coastguard Worker (iteration == 0) ? kStackBufferSize : dynamic_buffer_size; 61*9507f98cSAndroid Build Coastguard Worker char* const buffer = 62*9507f98cSAndroid Build Coastguard Worker (iteration == 0) ? stack_buffer : new char[dynamic_buffer_size]; 63*9507f98cSAndroid Build Coastguard Worker 64*9507f98cSAndroid Build Coastguard Worker // Print the header into the buffer. 65*9507f98cSAndroid Build Coastguard Worker int buffer_offset = std::snprintf( 66*9507f98cSAndroid Build Coastguard Worker buffer, buffer_size, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %s ", 67*9507f98cSAndroid Build Coastguard Worker now_components.tm_year + 1900, now_components.tm_mon + 1, 68*9507f98cSAndroid Build Coastguard Worker now_components.tm_mday, now_components.tm_hour, now_components.tm_min, 69*9507f98cSAndroid Build Coastguard Worker now_components.tm_sec, static_cast<int>(now_timeval.tv_usec), 70*9507f98cSAndroid Build Coastguard Worker thread_id.c_str()); 71*9507f98cSAndroid Build Coastguard Worker 72*9507f98cSAndroid Build Coastguard Worker // The header can be at most 28 characters (10 date + 15 time + 73*9507f98cSAndroid Build Coastguard Worker // 3 delimiters) plus the thread ID, which should fit comfortably into the 74*9507f98cSAndroid Build Coastguard Worker // static buffer. 75*9507f98cSAndroid Build Coastguard Worker assert(buffer_offset <= 28 + kMaxThreadIdSize); 76*9507f98cSAndroid Build Coastguard Worker static_assert(28 + kMaxThreadIdSize < kStackBufferSize, 77*9507f98cSAndroid Build Coastguard Worker "stack-allocated buffer may not fit the message header"); 78*9507f98cSAndroid Build Coastguard Worker assert(buffer_offset < buffer_size); 79*9507f98cSAndroid Build Coastguard Worker 80*9507f98cSAndroid Build Coastguard Worker // Print the message into the buffer. 81*9507f98cSAndroid Build Coastguard Worker std::va_list arguments_copy; 82*9507f98cSAndroid Build Coastguard Worker va_copy(arguments_copy, arguments); 83*9507f98cSAndroid Build Coastguard Worker buffer_offset += 84*9507f98cSAndroid Build Coastguard Worker std::vsnprintf(buffer + buffer_offset, buffer_size - buffer_offset, 85*9507f98cSAndroid Build Coastguard Worker format, arguments_copy); 86*9507f98cSAndroid Build Coastguard Worker va_end(arguments_copy); 87*9507f98cSAndroid Build Coastguard Worker 88*9507f98cSAndroid Build Coastguard Worker // The code below may append a newline at the end of the buffer, which 89*9507f98cSAndroid Build Coastguard Worker // requires an extra character. 90*9507f98cSAndroid Build Coastguard Worker if (buffer_offset >= buffer_size - 1) { 91*9507f98cSAndroid Build Coastguard Worker // The message did not fit into the buffer. 92*9507f98cSAndroid Build Coastguard Worker if (iteration == 0) { 93*9507f98cSAndroid Build Coastguard Worker // Re-run the loop and use a dynamically-allocated buffer. The buffer 94*9507f98cSAndroid Build Coastguard Worker // will be large enough for the log message, an extra newline and a 95*9507f98cSAndroid Build Coastguard Worker // null terminator. 96*9507f98cSAndroid Build Coastguard Worker dynamic_buffer_size = buffer_offset + 2; 97*9507f98cSAndroid Build Coastguard Worker continue; 98*9507f98cSAndroid Build Coastguard Worker } 99*9507f98cSAndroid Build Coastguard Worker 100*9507f98cSAndroid Build Coastguard Worker // The dynamically-allocated buffer was incorrectly sized. This should 101*9507f98cSAndroid Build Coastguard Worker // not happen, assuming a correct implementation of std::(v)snprintf. 102*9507f98cSAndroid Build Coastguard Worker // Fail in tests, recover by truncating the log message in production. 103*9507f98cSAndroid Build Coastguard Worker assert(false); 104*9507f98cSAndroid Build Coastguard Worker buffer_offset = buffer_size - 1; 105*9507f98cSAndroid Build Coastguard Worker } 106*9507f98cSAndroid Build Coastguard Worker 107*9507f98cSAndroid Build Coastguard Worker // Add a newline if necessary. 108*9507f98cSAndroid Build Coastguard Worker if (buffer[buffer_offset - 1] != '\n') { 109*9507f98cSAndroid Build Coastguard Worker buffer[buffer_offset] = '\n'; 110*9507f98cSAndroid Build Coastguard Worker ++buffer_offset; 111*9507f98cSAndroid Build Coastguard Worker } 112*9507f98cSAndroid Build Coastguard Worker 113*9507f98cSAndroid Build Coastguard Worker assert(buffer_offset <= buffer_size); 114*9507f98cSAndroid Build Coastguard Worker std::fwrite(buffer, 1, buffer_offset, fp_); 115*9507f98cSAndroid Build Coastguard Worker std::fflush(fp_); 116*9507f98cSAndroid Build Coastguard Worker 117*9507f98cSAndroid Build Coastguard Worker if (iteration != 0) { 118*9507f98cSAndroid Build Coastguard Worker delete[] buffer; 119*9507f98cSAndroid Build Coastguard Worker } 120*9507f98cSAndroid Build Coastguard Worker break; 121*9507f98cSAndroid Build Coastguard Worker } 122*9507f98cSAndroid Build Coastguard Worker } 123*9507f98cSAndroid Build Coastguard Worker 124*9507f98cSAndroid Build Coastguard Worker private: 125*9507f98cSAndroid Build Coastguard Worker std::FILE* const fp_; 126*9507f98cSAndroid Build Coastguard Worker }; 127*9507f98cSAndroid Build Coastguard Worker 128*9507f98cSAndroid Build Coastguard Worker } // namespace leveldb 129*9507f98cSAndroid Build Coastguard Worker 130*9507f98cSAndroid Build Coastguard Worker #endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ 131