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/LogStreamProcessor.h>
18 #include <folly/experimental/logging/LogStream.h>
19 #include <folly/experimental/logging/xlog.h>
23 LogStreamProcessor::LogStreamProcessor(
24 const LogCategory* category,
26 folly::StringPiece filename,
27 unsigned int lineNumber,
37 LogStreamProcessor::LogStreamProcessor(
38 XlogCategoryInfo<true>* categoryInfo,
40 folly::StringPiece categoryName,
41 bool isCategoryNameOverridden,
42 folly::StringPiece filename,
43 unsigned int lineNumber,
49 isCategoryNameOverridden,
55 LogStreamProcessor::LogStreamProcessor(
56 XlogFileScopeInfo* fileScopeInfo,
58 folly::StringPiece filename,
59 unsigned int lineNumber,
69 LogStreamProcessor::LogStreamProcessor(
70 const LogCategory* category,
72 folly::StringPiece filename,
73 unsigned int lineNumber,
75 std::string&& msg) noexcept
76 : category_{category},
79 lineNumber_{lineNumber},
80 message_{std::move(msg)},
84 LogCategory* getXlogCategory(
85 XlogCategoryInfo<true>* categoryInfo,
86 folly::StringPiece categoryName,
87 bool isCategoryNameOverridden) {
88 if (!categoryInfo->isInitialized()) {
89 return categoryInfo->init(categoryName, isCategoryNameOverridden);
91 return categoryInfo->getCategory(&xlog_detail::xlogFileScopeInfo);
94 LogCategory* getXlogCategory(XlogFileScopeInfo* fileScopeInfo) {
95 // By the time a LogStreamProcessor is created, the XlogFileScopeInfo object
96 // should have already been initialized to perform the log level check.
97 // Therefore we never need to check if it is initialized here.
98 return fileScopeInfo->category;
103 * Construct a LogStreamProcessor from an XlogCategoryInfo.
105 * We intentionally define this in LogStreamProcessor.cpp instead of
106 * LogStreamProcessor.h to avoid having it inlined at every XLOG() call site,
107 * to reduce the emitted code size.
109 LogStreamProcessor::LogStreamProcessor(
110 XlogCategoryInfo<true>* categoryInfo,
112 folly::StringPiece categoryName,
113 bool isCategoryNameOverridden,
114 folly::StringPiece filename,
115 unsigned int lineNumber,
117 std::string&& msg) noexcept
118 : category_{getXlogCategory(
121 isCategoryNameOverridden)},
124 lineNumber_{lineNumber},
125 message_{std::move(msg)},
129 * Construct a LogStreamProcessor from an XlogFileScopeInfo.
131 * We intentionally define this in LogStreamProcessor.cpp instead of
132 * LogStreamProcessor.h to avoid having it inlined at every XLOG() call site,
133 * to reduce the emitted code size.
135 LogStreamProcessor::LogStreamProcessor(
136 XlogFileScopeInfo* fileScopeInfo,
138 folly::StringPiece filename,
139 unsigned int lineNumber,
141 std::string&& msg) noexcept
142 : category_{getXlogCategory(fileScopeInfo)},
145 lineNumber_{lineNumber},
146 message_{std::move(msg)},
150 * We intentionally define the LogStreamProcessor destructor in
151 * LogStreamProcessor.cpp instead of LogStreamProcessor.h to avoid having it
152 * emitted inline at every log statement site. This helps reduce the emitted
153 * code size for each log statement.
155 LogStreamProcessor::~LogStreamProcessor() noexcept {
156 // The LogStreamProcessor destructor is responsible for logging the message.
157 // Doing this in the destructor avoids an separate function call to log the
158 // message being emitted inline at every log statement site.
162 void LogStreamProcessor::logNow() noexcept {
163 // Note that admitMessage() is not noexcept and theoretically may throw.
164 // However, the only exception that should be possible is std::bad_alloc if
165 // we fail to allocate memory. We intentionally let our noexcept specifier
166 // crash in that case, since the program likely won't be able to continue
169 // Any other error here is unexpected and we also want to fail hard
170 // in that situation too.
171 category_->admitMessage(LogMessage{category_,
175 extractMessageString(stream_)});
178 void LogStreamVoidify<true>::operator&(std::ostream& stream) {
179 // Non-fatal log messages wait until the LogStreamProcessor destructor to log
180 // the message. However for fatal messages we log immediately in the &
181 // operator, since it is marked noreturn.
183 // This does result in slightly larger emitted code for fatal log messages
184 // (since the operator & call cannot be completely omitted). However, fatal
185 // log messages should typically be much more rare than non-fatal messages,
186 // so the small amount of extra overhead shouldn't be a big deal.
187 auto& logStream = static_cast<LogStream&>(stream);
188 logStream.getProcessor()->logNow();
192 std::string LogStreamProcessor::extractMessageString(
193 LogStream& stream) noexcept {
194 if (stream.empty()) {
195 return std::move(message_);
198 if (message_.empty()) {
199 return stream.extractString();
201 message_.append(stream.extractString());
202 return std::move(message_);