作者: 谢瑞阳 10225101483 徐翔宇 10225101535
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
4.7 KiB

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