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 const LogCategory* category,
58 folly::StringPiece filename,
59 unsigned int lineNumber,
61 std::string&& msg) noexcept
62 : category_{category},
65 lineNumber_{lineNumber},
66 message_{std::move(msg)},
70 LogCategory* getXlogCategory(
71 XlogCategoryInfo<true>* categoryInfo,
72 folly::StringPiece categoryName,
73 bool isCategoryNameOverridden) {
74 if (!categoryInfo->isInitialized()) {
75 return categoryInfo->init(categoryName, isCategoryNameOverridden);
77 return categoryInfo->getCategory(&xlog_detail::xlogFileScopeInfo);
82 * Construct a LogStreamProcessor from an XlogCategoryInfo.
84 * We intentionally define this in LogStreamProcessor.cpp instead of
85 * LogStreamProcessor.h to avoid having it inlined at every XLOG() call site,
86 * to reduce the emitted code size.
88 LogStreamProcessor::LogStreamProcessor(
89 XlogCategoryInfo<true>* categoryInfo,
91 folly::StringPiece categoryName,
92 bool isCategoryNameOverridden,
93 folly::StringPiece filename,
94 unsigned int lineNumber,
96 std::string&& msg) noexcept
97 : category_{getXlogCategory(
100 isCategoryNameOverridden)},
103 lineNumber_{lineNumber},
104 message_{std::move(msg)},
107 #ifdef __INCLUDE_LEVEL__
109 LogCategory* getXlogCategory(XlogFileScopeInfo* fileScopeInfo) {
110 // By the time a LogStreamProcessor is created, the XlogFileScopeInfo object
111 // should have already been initialized to perform the log level check.
112 // Therefore we never need to check if it is initialized here.
113 return fileScopeInfo->category;
118 * Construct a LogStreamProcessor from an XlogFileScopeInfo.
120 * We intentionally define this in LogStreamProcessor.cpp instead of
121 * LogStreamProcessor.h to avoid having it inlined at every XLOG() call site,
122 * to reduce the emitted code size.
124 * This is only defined if __INCLUDE_LEVEL__ is available. The
125 * XlogFileScopeInfo APIs are only invoked if we can use __INCLUDE_LEVEL__ to
126 * tell that an XLOG() statement occurs in a non-header file. For compilers
127 * that do not support __INCLUDE_LEVEL__, the category information is always
128 * passed in as XlogCategoryInfo<true> rather than as XlogFileScopeInfo.
130 LogStreamProcessor::LogStreamProcessor(
131 XlogFileScopeInfo* fileScopeInfo,
133 folly::StringPiece filename,
134 unsigned int lineNumber,
136 std::string&& msg) noexcept
137 : category_{getXlogCategory(fileScopeInfo)},
140 lineNumber_{lineNumber},
141 message_{std::move(msg)},
144 LogStreamProcessor::LogStreamProcessor(
145 XlogFileScopeInfo* fileScopeInfo,
147 folly::StringPiece filename,
148 unsigned int lineNumber,
150 : LogStreamProcessor(
160 * We intentionally define the LogStreamProcessor destructor in
161 * LogStreamProcessor.cpp instead of LogStreamProcessor.h to avoid having it
162 * emitted inline at every log statement site. This helps reduce the emitted
163 * code size for each log statement.
165 LogStreamProcessor::~LogStreamProcessor() noexcept {
166 // The LogStreamProcessor destructor is responsible for logging the message.
167 // Doing this in the destructor avoids an separate function call to log the
168 // message being emitted inline at every log statement site.
172 void LogStreamProcessor::logNow() noexcept {
173 // Note that admitMessage() is not noexcept and theoretically may throw.
174 // However, the only exception that should be possible is std::bad_alloc if
175 // we fail to allocate memory. We intentionally let our noexcept specifier
176 // crash in that case, since the program likely won't be able to continue
179 // Any other error here is unexpected and we also want to fail hard
180 // in that situation too.
181 category_->admitMessage(LogMessage{category_,
185 extractMessageString(stream_)});
188 std::string LogStreamProcessor::extractMessageString(
189 LogStream& stream) noexcept {
190 if (stream.empty()) {
191 return std::move(message_);
194 if (message_.empty()) {
195 return stream.extractString();
197 message_.append(stream.extractString());
198 return std::move(message_);
201 void LogStreamVoidify<true>::operator&(std::ostream& stream) {
202 // Non-fatal log messages wait until the LogStreamProcessor destructor to log
203 // the message. However for fatal messages we log immediately in the &
204 // operator, since it is marked noreturn.
206 // This does result in slightly larger emitted code for fatal log messages
207 // (since the operator & call cannot be completely omitted). However, fatal
208 // log messages should typically be much more rare than non-fatal messages,
209 // so the small amount of extra overhead shouldn't be a big deal.
210 auto& logStream = static_cast<LogStream&>(stream);
211 logStream.getProcessor()->logNow();
215 void logDisabledHelper(std::integral_constant<bool, true>) noexcept {
216 // This function can only be reached if we had a disabled fatal log message.
217 // This should never happen: LogCategory::setLevelLocked() does not allow
218 // setting the threshold for a category lower than FATAL (in production
219 // builds) or DFATAL (in debug builds).