小组成员:10215300402-朱维清 & 10222140408 谷杰
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.

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