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.
18 #include <folly/Conv.h>
19 #include <folly/Demangle.h>
20 #include <folly/Format.h>
21 #include <folly/experimental/logging/LogCategory.h>
22 #include <folly/experimental/logging/LogMessage.h>
29 * Helper functions for fallback-formatting of arguments if folly::format()
30 * throws an exception.
32 * These are in a detail namespace so that we can include a using directive in
33 * order to do proper argument-dependent lookup of the correct toAppend()
38 using folly::toAppend;
39 template <typename Arg>
40 auto fallbackFormatOneArg(std::string* str, const Arg* arg, int) -> decltype(
41 toAppend(std::declval<Arg>(), std::declval<std::string*>()),
42 std::declval<void>()) {
46 toAppend(folly::demangle(typeid(*arg)), str);
50 } catch (const std::exception&) {
51 str->append("<error_converting_to_string>");
56 template <typename Arg>
57 inline void fallbackFormatOneArg(std::string* str, const Arg* arg, long) {
61 toAppend(folly::demangle(typeid(*arg)), str);
63 } catch (const std::exception&) {
67 str->append("<no_string_conversion>)");
72 * LogStreamProcessor receives a LogStream and logs it.
74 * This class is primarily intended to be used through the FB_LOG*() macros.
75 * Its API is designed to support these macros, and is not designed for other
78 * The operator&() method is used to trigger the logging.
79 * This operator is used because it has lower precedence than <<, but higher
80 * precedence than the ? ternary operator, allowing it to bind with the correct
81 * precedence in the log macro implementations.
83 class LogStreamProcessor {
85 enum AppendType { APPEND };
86 enum FormatType { FORMAT };
89 * LogStreamProcessor constructor for use with a LOG() macro with no extra
92 * Note that the filename argument is not copied. The caller should ensure
93 * that it points to storage that will remain valid for the lifetime of the
94 * LogStreamProcessor. (This is always the case for the __FILE__
95 * preprocessor macro.)
98 const LogCategory* category,
100 folly::StringPiece filename,
101 unsigned int lineNumber,
103 : category_{category},
106 lineNumber_{lineNumber} {}
109 * LogStreamProcessor constructor for use with a LOG() macro with arguments
110 * to be concatenated with folly::to<std::string>()
112 * Note that the filename argument is not copied. The caller should ensure
113 * that it points to storage that will remain valid for the lifetime of the
114 * LogStreamProcessor. (This is always the case for the __FILE__
115 * preprocessor macro.)
117 template <typename... Args>
119 const LogCategory* category,
121 const char* filename,
122 unsigned int lineNumber,
124 Args&&... args) noexcept
125 : category_{category},
128 lineNumber_{lineNumber},
129 message_{createLogString(std::forward<Args>(args)...)} {}
132 * LogStreamProcessor constructor for use with a LOG() macro with arguments
133 * to be concatenated with folly::to<std::string>()
135 * Note that the filename argument is not copied. The caller should ensure
136 * that it points to storage that will remain valid for the lifetime of the
137 * LogStreamProcessor. (This is always the case for the __FILE__
138 * preprocessor macro.)
140 template <typename... Args>
142 const LogCategory* category,
144 const char* filename,
145 unsigned int lineNumber,
147 folly::StringPiece fmt,
148 Args&&... args) noexcept
149 : category_{category},
152 lineNumber_{lineNumber},
153 message_{formatLogString(fmt, std::forward<Args>(args)...)} {}
156 * This version of operator&() is typically used when the user specifies
157 * log arguments using the << stream operator. The operator<<() generally
158 * returns a std::ostream&
160 void operator&(std::ostream& stream) noexcept;
163 * This version of operator&() is used when no extra arguments are specified
164 * with the << operator. In this case the & operator is applied directly to
165 * the temporary LogStream object.
167 void operator&(LogStream&& stream) noexcept;
170 std::string extractMessageString(LogStream& stream) noexcept;
173 * Construct a log message string using folly::to<std::string>()
175 * This function attempts to avoid throwing exceptions. If an error occurs
176 * during formatting, a message including the error details is returned
177 * instead. This is done to help ensure that log statements do not generate
178 * exceptions, but instead just log an error string when something goes wrong.
180 template <typename... Args>
181 std::string createLogString(Args&&... args) noexcept {
183 return folly::to<std::string>(std::forward<Args>(args)...);
184 } catch (const std::exception& ex) {
185 // This most likely means there was some error converting the arguments
186 // to strings. Handle the exception here, rather than letting it
187 // propagate up, since callers generally do not expect log statements to
190 // Just log an error message letting indicating that something went wrong
191 // formatting the log message.
192 return folly::to<std::string>(
193 "error constructing log message: ", ex.what());
198 * Construct a log message string using folly::sformat()
200 * This function attempts to avoid throwing exceptions. If an error occurs
201 * during formatting, a message including the error details is returned
202 * instead. This is done to help ensure that log statements do not generate
203 * exceptions, but instead just log an error string when something goes wrong.
205 template <typename... Args>
206 std::string formatLogString(
207 folly::StringPiece fmt,
208 const Args&... args) noexcept {
210 return folly::sformat(fmt, args...);
211 } catch (const std::exception& ex) {
212 // This most likely means that the caller had a bug in their format
213 // string/arguments. Handle the exception here, rather than letting it
214 // propagate up, since callers generally do not expect log statements to
217 // Log the format string and as much of the arguments as we can convert,
220 result.append("error formatting log message: ");
221 result.append(ex.what());
222 result.append("; format string: \"");
223 result.append(fmt.data(), fmt.size());
224 result.append("\", arguments: ");
225 fallbackFormat(&result, args...);
231 * Helper function generate a fallback version of the arguments in case
232 * folly::sformat() throws an exception.
234 * This attempts to convert each argument to a string using a similar
235 * mechanism to folly::to<std::string>(), if supported.
237 template <typename Arg1, typename... Args>
239 fallbackFormat(std::string* str, const Arg1& arg1, const Args&... remainder) {
240 detail::fallbackFormatOneArg(str, &arg1, 0);
242 fallbackFormat(str, remainder...);
245 template <typename Arg>
246 void fallbackFormat(std::string* str, const Arg& arg) {
247 detail::fallbackFormatOneArg(str, &arg, 0);
250 const LogCategory* const category_;
251 LogLevel const level_;
252 folly::StringPiece filename_;
253 unsigned int lineNumber_;
254 std::string message_;