1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. See the AUTHORS file for names of contributors. 4 // 5 // Logger implementation that can be shared by all environments 6 // where enough posix functionality is available. 7 8 #ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ 9 #define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ 10 11 #include <algorithm> 12 #include <stdio.h> 13 #include <sys/time.h> 14 #include <time.h> 15 #include "leveldb/env.h" 16 17 namespace leveldb { 18 19 class PosixLogger : public Logger { 20 private: 21 FILE* file_; 22 uint64_t (*gettid_)(); // Return the thread id for the current thread 23 public: 24 PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { } 25 virtual ~PosixLogger() { 26 fclose(file_); 27 } 28 virtual void Logv(const char* format, va_list ap) { 29 const uint64_t thread_id = (*gettid_)(); 30 31 // We try twice: the first time with a fixed-size stack allocated buffer, 32 // and the second time with a much larger dynamically allocated buffer. 33 char buffer[500]; 34 for (int iter = 0; iter < 2; iter++) { 35 char* base; 36 int bufsize; 37 if (iter == 0) { 38 bufsize = sizeof(buffer); 39 base = buffer; 40 } else { 41 bufsize = 30000; 42 base = new char[bufsize]; 43 } 44 char* p = base; 45 char* limit = base + bufsize; 46 47 struct timeval now_tv; 48 gettimeofday(&now_tv, NULL); 49 const time_t seconds = now_tv.tv_sec; 50 struct tm t; 51 localtime_r(&seconds, &t); 52 p += snprintf(p, limit - p, 53 "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", 54 t.tm_year + 1900, 55 t.tm_mon + 1, 56 t.tm_mday, 57 t.tm_hour, 58 t.tm_min, 59 t.tm_sec, 60 static_cast<int>(now_tv.tv_usec), 61 static_cast<long long unsigned int>(thread_id)); 62 63 // Print the message 64 if (p < limit) { 65 va_list backup_ap; 66 va_copy(backup_ap, ap); 67 p += vsnprintf(p, limit - p, format, backup_ap); 68 va_end(backup_ap); 69 } 70 71 // Truncate to available space if necessary 72 if (p >= limit) { 73 if (iter == 0) { 74 continue; // Try again with larger buffer 75 } else { 76 p = limit - 1; 77 } 78 } 79 80 // Add newline if necessary 81 if (p == base || p[-1] != '\n') { 82 *p++ = '\n'; 83 } 84 85 assert(p <= limit); 86 fwrite(base, 1, p - base, file_); 87 fflush(file_); 88 if (base != buffer) { 89 delete[] base; 90 } 91 break; 92 } 93 } 94 }; 95 96 } // namespace leveldb 97 98 #endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ 99