LogMessage.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/logging/LogMessage.h>
  17. #include <folly/system/ThreadId.h>
  18. using std::chrono::system_clock;
  19. namespace folly {
  20. LogMessage::LogMessage(
  21. const LogCategory* category,
  22. LogLevel level,
  23. StringPiece filename,
  24. unsigned int lineNumber,
  25. StringPiece functionName,
  26. std::string&& msg)
  27. : category_{category},
  28. level_{level},
  29. threadID_{getOSThreadID()},
  30. timestamp_{system_clock::now()},
  31. filename_{filename},
  32. lineNumber_{lineNumber},
  33. functionName_{functionName},
  34. rawMessage_{std::move(msg)} {
  35. sanitizeMessage();
  36. }
  37. LogMessage::LogMessage(
  38. const LogCategory* category,
  39. LogLevel level,
  40. system_clock::time_point timestamp,
  41. StringPiece filename,
  42. unsigned int lineNumber,
  43. StringPiece functionName,
  44. std::string&& msg)
  45. : category_{category},
  46. level_{level},
  47. threadID_{getOSThreadID()},
  48. timestamp_{timestamp},
  49. filename_{filename},
  50. lineNumber_{lineNumber},
  51. functionName_{functionName},
  52. rawMessage_{std::move(msg)} {
  53. sanitizeMessage();
  54. }
  55. StringPiece LogMessage::getFileBaseName() const {
  56. #if _WIN32
  57. // Windows allows either backwards or forwards slash as path separator
  58. auto idx1 = filename_.rfind('\\');
  59. auto idx2 = filename_.rfind('/');
  60. StringPiece::size_type idx;
  61. if (idx1 == StringPiece::npos) {
  62. idx = idx2;
  63. } else if (idx2 == StringPiece::npos) {
  64. idx = idx1;
  65. } else {
  66. idx = std::max(idx1, idx2);
  67. }
  68. #else
  69. auto idx = filename_.rfind('/');
  70. #endif
  71. if (idx == StringPiece::npos) {
  72. return filename_;
  73. }
  74. return filename_.subpiece(idx + 1);
  75. }
  76. void LogMessage::sanitizeMessage() {
  77. // Compute how long the sanitized string will be.
  78. size_t sanitizedLength = 0;
  79. for (const char c : rawMessage_) {
  80. if (c == '\\') {
  81. // Backslashes are escaped as two backslashes
  82. sanitizedLength += 2;
  83. } else if (static_cast<unsigned char>(c) < 0x20) {
  84. // Newlines and tabs are emitted directly with no escaping.
  85. // All other control characters are emitted as \xNN (4 characters)
  86. if (c == '\n') {
  87. sanitizedLength += 1;
  88. containsNewlines_ = true;
  89. } else if (c == '\t') {
  90. sanitizedLength += 1;
  91. } else {
  92. sanitizedLength += 4;
  93. }
  94. } else if (c == 0x7f) {
  95. // Bytes above the ASCII range are emitted as \xNN (4 characters)
  96. sanitizedLength += 4;
  97. } else {
  98. // This character will be emitted as-is, with no escaping.
  99. ++sanitizedLength;
  100. }
  101. }
  102. // If nothing is different, just use rawMessage_ directly,
  103. // and don't populate message_.
  104. if (sanitizedLength == rawMessage_.size()) {
  105. return;
  106. }
  107. message_.reserve(sanitizedLength);
  108. for (const char c : rawMessage_) {
  109. if (c == '\\') {
  110. message_.push_back('\\');
  111. message_.push_back('\\');
  112. } else if (static_cast<unsigned char>(c) < 0x20) {
  113. if (c == '\n' || c == '\t') {
  114. message_.push_back(c);
  115. } else {
  116. static constexpr StringPiece hexdigits{"0123456789abcdef"};
  117. std::array<char, 4> data{
  118. {'\\', 'x', hexdigits[(c >> 4) & 0xf], hexdigits[c & 0xf]}};
  119. message_.append(data.data(), data.size());
  120. }
  121. } else if (c == 0x7f) {
  122. constexpr std::array<char, 4> data{{'\\', 'x', '7', 'f'}};
  123. message_.append(data.data(), data.size());
  124. } else {
  125. message_.push_back(c);
  126. }
  127. }
  128. }
  129. } // namespace folly