LCOV - code coverage report
Current view: top level - src/leveldb/util - posix_logger.h (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 44 0
Test Date: 2026-02-04 04:43:42 Functions: 0.0 % 4 0
Branches: 0.0 % 44 0

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

Generated by: LCOV version 2.0-1