xref: /aosp_15_r20/external/leveldb/util/posix_logger.h (revision 9507f98c5f32dee4b5f9e4a38cd499f3ff5c4490)
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