2 * Copyright 2004-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <folly/experimental/logging/LogMessage.h>
18 #include <folly/ThreadId.h>
20 using std::chrono::system_clock;
24 LogMessage::LogMessage(
25 const LogCategory* category,
28 unsigned int lineNumber,
30 : category_{category},
32 threadID_{getOSThreadID()},
33 timestamp_{system_clock::now()},
35 lineNumber_{lineNumber},
36 rawMessage_{std::move(msg)} {
40 LogMessage::LogMessage(
41 const LogCategory* category,
43 system_clock::time_point timestamp,
45 unsigned int lineNumber,
47 : category_{category},
49 threadID_{getOSThreadID()},
50 timestamp_{timestamp},
52 lineNumber_{lineNumber},
53 rawMessage_{std::move(msg)} {
57 StringPiece LogMessage::getFileBaseName() const {
59 // Windows allows either backwards or forwards slash as path separator
60 auto idx1 = filename_.rfind('\\');
61 auto idx2 = filename_.rfind('/');
62 StringPiece::size_type idx;
63 if (idx1 == StringPiece::npos) {
65 } else if (idx2 == StringPiece::npos) {
68 idx = std::max(idx1, idx2);
71 auto idx = filename_.rfind('/');
73 if (idx == StringPiece::npos) {
76 return filename_.subpiece(idx + 1);
79 void LogMessage::sanitizeMessage() {
80 // Compute how long the sanitized string will be.
81 size_t sanitizedLength = 0;
82 for (const char c : rawMessage_) {
84 // Backslashes are escaped as two backslashes
86 } else if (static_cast<unsigned char>(c) < 0x20) {
87 // Newlines and tabs are emitted directly with no escaping.
88 // All other control characters are emitted as \xNN (4 characters)
91 containsNewlines_ = true;
92 } else if (c == '\t') {
97 } else if (c == 0x7f) {
98 // Bytes above the ASCII range are emitted as \xNN (4 characters)
101 // This character will be emitted as-is, with no escaping.
106 // If nothing is different, just use rawMessage_ directly,
107 // and don't populate message_.
108 if (sanitizedLength == rawMessage_.size()) {
112 message_.reserve(sanitizedLength);
113 for (const char c : rawMessage_) {
115 message_.push_back('\\');
116 message_.push_back('\\');
117 } else if (static_cast<unsigned char>(c) < 0x20) {
118 if (c == '\n' || c == '\t') {
119 message_.push_back(c);
121 static constexpr StringPiece hexdigits{"0123456789abcdef"};
122 std::array<char, 4> data{
123 {'\\', 'x', hexdigits[(c >> 4) & 0xf], hexdigits[c & 0xf]}};
124 message_.append(data.data(), data.size());
126 } else if (c == 0x7f) {
127 constexpr std::array<char, 4> data{{'\\', 'x', '7', 'f'}};
128 message_.append(data.data(), data.size());
130 message_.push_back(c);