proxygen
LogStreamProcessor.h
Go to the documentation of this file.
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 #pragma once
17 
18 #include <folly/CPortability.h>
19 #include <folly/Conv.h>
20 #include <folly/Demangle.h>
21 #include <folly/Format.h>
22 #include <folly/Portability.h>
26 #include <cstdlib>
27 
28 namespace folly {
29 
30 /*
31  * Helper functions for fallback-formatting of arguments if folly::format()
32  * throws an exception.
33  *
34  * These are in a detail namespace so that we can include a using directive in
35  * order to do proper argument-dependent lookup of the correct toAppend()
36  * function to use.
37  */
38 namespace detail {
39 /* using override */
40 using folly::toAppend;
41 template <typename Arg>
42 auto fallbackFormatOneArg(std::string* str, const Arg* arg, int) -> decltype(
43  toAppend(std::declval<Arg>(), std::declval<std::string*>()),
44  std::declval<void>()) {
45  str->push_back('(');
46  try {
47 #ifdef FOLLY_HAS_RTTI
48  toAppend(folly::demangle(typeid(*arg)), str);
49  str->append(": ");
50 #endif
51  toAppend(*arg, str);
52  } catch (const std::exception&) {
53  str->append("<error_converting_to_string>");
54  }
55  str->push_back(')');
56 }
57 
58 template <typename Arg>
59 inline void fallbackFormatOneArg(std::string* str, const Arg* arg, long) {
60  str->push_back('(');
61 #ifdef FOLLY_HAS_RTTI
62  try {
63  toAppend(folly::demangle(typeid(*arg)), str);
64  str->append(": ");
65  } catch (const std::exception&) {
66  // Ignore the error
67  }
68 #endif
69  str->append("<no_string_conversion>)");
70 }
71 } // namespace detail
72 
73 template <bool IsInHeaderFile>
75 class XlogFileScopeInfo;
76 
90  public:
91  enum AppendType { APPEND };
92  enum FormatType { FORMAT };
93 
104  const LogCategory* category,
105  LogLevel level,
106  folly::StringPiece filename,
107  unsigned int lineNumber,
108  folly::StringPiece functionName,
110 
120  template <typename... Args>
122  const LogCategory* category,
123  LogLevel level,
124  folly::StringPiece filename,
125  unsigned int lineNumber,
126  folly::StringPiece functionName,
127  AppendType,
128  Args&&... args) noexcept
130  category,
131  level,
132  filename,
133  lineNumber,
134  functionName,
135  INTERNAL,
136  createLogString(std::forward<Args>(args)...)) {}
137 
147  template <typename... Args>
149  const LogCategory* category,
150  LogLevel level,
151  folly::StringPiece filename,
152  unsigned int lineNumber,
153  folly::StringPiece functionName,
154  FormatType,
155  folly::StringPiece fmt,
156  Args&&... args) noexcept
158  category,
159  level,
160  filename,
161  lineNumber,
162  functionName,
163  INTERNAL,
164  formatLogString(fmt, std::forward<Args>(args)...)) {}
165 
166  /*
167  * Versions of the above constructors for use in XLOG() statements.
168  *
169  * These are defined separately from the above constructor so that the work
170  * of initializing the XLOG LogCategory data is done in a separate function
171  * body defined in LogStreamProcessor.cpp. We intentionally want to avoid
172  * inlining this work at every XLOG() statement, to reduce the emitted code
173  * size.
174  */
176  XlogCategoryInfo<true>* categoryInfo,
177  LogLevel level,
178  folly::StringPiece categoryName,
179  bool isCategoryNameOverridden,
180  folly::StringPiece filename,
181  unsigned int lineNumber,
182  folly::StringPiece functionName,
184  template <typename... Args>
186  XlogCategoryInfo<true>* categoryInfo,
187  LogLevel level,
188  folly::StringPiece categoryName,
189  bool isCategoryNameOverridden,
190  folly::StringPiece filename,
191  unsigned int lineNumber,
192  folly::StringPiece functionName,
193  AppendType,
194  Args&&... args) noexcept
196  categoryInfo,
197  level,
198  categoryName,
199  isCategoryNameOverridden,
200  filename,
201  lineNumber,
202  functionName,
203  INTERNAL,
204  createLogString(std::forward<Args>(args)...)) {}
205  template <typename... Args>
207  XlogCategoryInfo<true>* categoryInfo,
208  LogLevel level,
209  folly::StringPiece categoryName,
210  bool isCategoryNameOverridden,
211  folly::StringPiece filename,
212  unsigned int lineNumber,
213  folly::StringPiece functionName,
214  FormatType,
215  folly::StringPiece fmt,
216  Args&&... args) noexcept
218  categoryInfo,
219  level,
220  categoryName,
221  isCategoryNameOverridden,
222  filename,
223  lineNumber,
224  functionName,
225  INTERNAL,
226  formatLogString(fmt, std::forward<Args>(args)...)) {}
227 
228 #ifdef __INCLUDE_LEVEL__
229  /*
230  * Versions of the above constructors to use in XLOG() macros that appear in
231  * .cpp files. These are only used if the compiler supports the
232  * __INCLUDE_LEVEL__ macro, which we need to determine that the XLOG()
233  * statement is not in a header file.
234  *
235  * These behave identically to the XlogCategoryInfo<true> versions of the
236  * APIs, but slightly more optimized, and allow the XLOG() code to avoid
237  * storing category information at each XLOG() call site.
238  */
240  XlogFileScopeInfo* fileScopeInfo,
241  LogLevel level,
242  folly::StringPiece filename,
243  unsigned int lineNumber,
244  folly::StringPiece functionName,
247  XlogFileScopeInfo* fileScopeInfo,
248  LogLevel level,
249  folly::StringPiece /* categoryName */,
250  bool /* isCategoryNameOverridden */,
251  folly::StringPiece filename,
252  unsigned int lineNumber,
253  folly::StringPiece functionName,
256  fileScopeInfo,
257  level,
258  filename,
259  lineNumber,
260  functionName,
261  APPEND) {}
262  template <typename... Args>
264  XlogFileScopeInfo* fileScopeInfo,
265  LogLevel level,
266  folly::StringPiece /* categoryName */,
267  bool /* isCategoryNameOverridden */,
268  folly::StringPiece filename,
269  unsigned int lineNumber,
270  folly::StringPiece functionName,
271  AppendType,
272  Args&&... args) noexcept
274  fileScopeInfo,
275  level,
276  filename,
277  lineNumber,
278  functionName,
279  INTERNAL,
280  createLogString(std::forward<Args>(args)...)) {}
281  template <typename... Args>
283  XlogFileScopeInfo* fileScopeInfo,
284  LogLevel level,
285  folly::StringPiece /* categoryName */,
286  bool /* isCategoryNameOverridden */,
287  folly::StringPiece filename,
288  unsigned int lineNumber,
289  folly::StringPiece functionName,
290  FormatType,
291  folly::StringPiece fmt,
292  Args&&... args) noexcept
294  fileScopeInfo,
295  level,
296  filename,
297  lineNumber,
298  functionName,
299  INTERNAL,
300  formatLogString(fmt, std::forward<Args>(args)...)) {}
301 #endif
302 
304 
310  void operator&(std::ostream& stream) noexcept;
311 
317  void operator&(LogStream&& stream) noexcept;
318 
319  std::ostream& stream() noexcept {
320  return stream_;
321  }
322 
323  void logNow() noexcept;
324 
325  private:
326  enum InternalType { INTERNAL };
328  const LogCategory* category,
329  LogLevel level,
330  folly::StringPiece filename,
331  unsigned int lineNumber,
332  folly::StringPiece functionName,
333  InternalType,
334  std::string&& msg) noexcept;
336  XlogCategoryInfo<true>* categoryInfo,
337  LogLevel level,
338  folly::StringPiece categoryName,
339  bool isCategoryNameOverridden,
340  folly::StringPiece filename,
341  unsigned int lineNumber,
342  folly::StringPiece functionName,
343  InternalType,
344  std::string&& msg) noexcept;
346  XlogFileScopeInfo* fileScopeInfo,
347  LogLevel level,
348  folly::StringPiece filename,
349  unsigned int lineNumber,
350  folly::StringPiece functionName,
351  InternalType,
352  std::string&& msg) noexcept;
353 
354  std::string extractMessageString(LogStream& stream) noexcept;
355 
364  template <typename... Args>
366  try {
367  return folly::to<std::string>(std::forward<Args>(args)...);
368  } catch (const std::exception& ex) {
369  // This most likely means there was some error converting the arguments
370  // to strings. Handle the exception here, rather than letting it
371  // propagate up, since callers generally do not expect log statements to
372  // throw.
373  //
374  // Just log an error message letting indicating that something went wrong
375  // formatting the log message.
376  return folly::to<std::string>(
377  "error constructing log message: ", ex.what());
378  }
379  }
380 
389  template <typename... Args>
391  folly::StringPiece fmt,
392  const Args&... args) noexcept {
393  try {
394  return folly::sformat(fmt, args...);
395  } catch (const std::exception& ex) {
396  // This most likely means that the caller had a bug in their format
397  // string/arguments. Handle the exception here, rather than letting it
398  // propagate up, since callers generally do not expect log statements to
399  // throw.
400  //
401  // Log the format string and as much of the arguments as we can convert,
402  // to aid debugging.
403  std::string result;
404  result.append("error formatting log message: ");
405  result.append(ex.what());
406  result.append("; format string: \"");
407  result.append(fmt.data(), fmt.size());
408  result.append("\", arguments: ");
409  fallbackFormat(&result, args...);
410  return result;
411  }
412  }
413 
421  template <typename Arg1, typename... Args>
422  void
423  fallbackFormat(std::string* str, const Arg1& arg1, const Args&... remainder) {
424  detail::fallbackFormatOneArg(str, &arg1, 0);
425  str->append(", ");
426  fallbackFormat(str, remainder...);
427  }
428 
429  template <typename Arg>
430  void fallbackFormat(std::string* str, const Arg& arg) {
431  detail::fallbackFormatOneArg(str, &arg, 0);
432  }
433 
434  const LogCategory* const category_;
437  unsigned int lineNumber_;
441 };
442 
464 template <bool Fatal>
466  public:
483  void operator&(std::ostream&)noexcept {}
484 };
485 
486 template <>
487 class LogStreamVoidify<true> {
488  public:
492  [[noreturn]] void operator&(std::ostream&);
493 };
494 
519 // clang-format off
521 [[noreturn]] void logDisabledHelper(std::true_type) noexcept;
522 // clang-format on
523 } // namespace folly
folly::StringPiece filename_
LogStreamProcessor(const LogCategory *category, LogLevel level, folly::StringPiece filename, unsigned int lineNumber, folly::StringPiece functionName, AppendType, Args &&...args) noexcept
std::ostream & stream() noexcept
void logDisabledHelper(std::true_type) noexcept
void operator&(std::ostream &) noexcept
FOLLY_NOINLINE std::string createLogString(Args &&...args) noexcept
const LogCategory *const category_
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
STL namespace.
constexpr size_type size() const
Definition: Range.h:431
WriteFlags operator&(WriteFlags a, WriteFlags b)
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
void fallbackFormat(std::string *str, const Arg1 &arg1, const Args &...remainder)
LogStreamProcessor(const LogCategory *category, LogLevel level, folly::StringPiece filename, unsigned int lineNumber, folly::StringPiece functionName, FormatType, folly::StringPiece fmt, Args &&...args) noexcept
void fallbackFormat(std::string *str, const Arg &arg)
bool_constant< true > true_type
Definition: gtest-port.h:2210
#define FOLLY_NOINLINE
Definition: CPortability.h:142
LogStreamProcessor(XlogCategoryInfo< true > *categoryInfo, LogLevel level, folly::StringPiece categoryName, bool isCategoryNameOverridden, folly::StringPiece filename, unsigned int lineNumber, folly::StringPiece functionName, FormatType, folly::StringPiece fmt, Args &&...args) noexcept
constexpr Iter data() const
Definition: Range.h:446
LogStreamProcessor(XlogCategoryInfo< true > *categoryInfo, LogLevel level, folly::StringPiece categoryName, bool isCategoryNameOverridden, folly::StringPiece filename, unsigned int lineNumber, folly::StringPiece functionName, AppendType, Args &&...args) noexcept
LogLevel
Definition: LogLevel.h:38
void toAppend(char value, Tgt *result)
Definition: Conv.h:406
auto fallbackFormatOneArg(std::string *str, const Arg *arg, int) -> decltype(toAppend(std::declval< Arg >(), std::declval< std::string * >()), std::declval< void >())
const char * string
Definition: Conv.cpp:212
bool_constant< false > false_type
Definition: gtest-port.h:2209
folly::StringPiece functionName_
fbstring demangle(const char *name)
Definition: Demangle.cpp:111
FOLLY_NOINLINE std::string formatLogString(folly::StringPiece fmt, const Args &...args) noexcept