chromium_logger.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright (c) 2012 The Chromium 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.
  4. #ifndef THIRD_PARTY_LEVELDATABASE_CHROMIUM_LOGGER_H_
  5. #define THIRD_PARTY_LEVELDATABASE_CHROMIUM_LOGGER_H_
  6. #include <cstdarg>
  7. #include <utility>
  8. #include "base/files/file.h"
  9. #include "base/format_macros.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/threading/platform_thread.h"
  12. #include "base/time/time.h"
  13. namespace leveldb {
  14. class ChromiumLogger : public Logger {
  15. public:
  16. explicit ChromiumLogger(base::File file) : file_(std::move(file)) {}
  17. ~ChromiumLogger() override = default;
  18. void Logv(const char* format, va_list arguments) override {
  19. // Record the time as close to the Logv() call as possible.
  20. base::Time::Exploded now_exploded;
  21. base::Time::Now().LocalExplode(&now_exploded);
  22. const base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
  23. // We first attempt to print into a stack-allocated buffer. If this attempt
  24. // fails, we make a second attempt with a dynamically allocated buffer.
  25. constexpr const int kStackBufferSize = 512;
  26. char stack_buffer[kStackBufferSize];
  27. static_assert(sizeof(stack_buffer) == static_cast<size_t>(kStackBufferSize),
  28. "sizeof(char) is expected to be 1 in C++");
  29. int dynamic_buffer_size = 0; // Computed in the first iteration.
  30. for (int iteration = 0; iteration < 2; ++iteration) {
  31. const int buffer_size =
  32. (iteration == 0) ? kStackBufferSize : dynamic_buffer_size;
  33. char* const buffer =
  34. (iteration == 0) ? stack_buffer : new char[dynamic_buffer_size];
  35. // Print the header into the buffer.
  36. int buffer_offset = base::snprintf(
  37. buffer, buffer_size,
  38. "%04d/%02d/%02d-%02d:%02d:%02d.%03d %" PRIx64 " ",
  39. now_exploded.year,
  40. now_exploded.month,
  41. now_exploded.day_of_month,
  42. now_exploded.hour,
  43. now_exploded.minute,
  44. now_exploded.second,
  45. now_exploded.millisecond,
  46. static_cast<uint64_t>(thread_id));
  47. // The header can be at most 45 characters (10 date + 12 time + 3 spacing
  48. // + 20 thread ID), which should fit comfortably into the static buffer.
  49. DCHECK_LE(buffer_offset, 45);
  50. static_assert(45 < kStackBufferSize,
  51. "stack-allocated buffer may not fit the message header");
  52. DCHECK_LT(buffer_offset, buffer_size);
  53. // Print the message into the buffer.
  54. std::va_list arguments_copy;
  55. va_copy(arguments_copy, arguments);
  56. buffer_offset += std::vsnprintf(buffer + buffer_offset,
  57. buffer_size - buffer_offset, format,
  58. arguments_copy);
  59. va_end(arguments_copy);
  60. // The code below may append a newline at the end of the buffer, which
  61. // requires an extra character.
  62. if (buffer_offset >= buffer_size - 1) {
  63. // The message did not fit into the buffer.
  64. if (iteration == 0) {
  65. // Re-run the loop and use a dynamically-allocated buffer. The buffer
  66. // will be large enough for the log message, an extra newline and a
  67. // null terminator.
  68. dynamic_buffer_size = buffer_offset + 2;
  69. continue;
  70. }
  71. // The dynamically-allocated buffer was incorrectly sized. This should
  72. // not happen, assuming a correct implementation of (v)snprintf. Fail
  73. // in tests, recover by truncating the log message in production.
  74. NOTREACHED();
  75. buffer_offset = buffer_size - 1;
  76. }
  77. // Add a newline if necessary.
  78. if (buffer[buffer_offset - 1] != '\n') {
  79. buffer[buffer_offset] = '\n';
  80. ++buffer_offset;
  81. }
  82. DCHECK_LE(buffer_offset, buffer_size);
  83. file_.WriteAtCurrentPos(buffer, buffer_offset);
  84. if (iteration != 0) {
  85. delete[] buffer;
  86. }
  87. break;
  88. }
  89. }
  90. private:
  91. base::File file_;
  92. };
  93. } // namespace leveldb
  94. #endif // THIRD_PARTY_LEVELDATABASE_CHROMIUM_LOGGER_H_