folly/folly/logging/LogStreamProcessor.h

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <cstdlib>

#include <fmt/core.h>
#include <folly/CPortability.h>
#include <folly/Conv.h>
#include <folly/ExceptionString.h>
#include <folly/Portability.h>
#include <folly/lang/Exception.h>
#include <folly/logging/LogCategory.h>
#include <folly/logging/LogMessage.h>
#include <folly/logging/LogStream.h>
#include <folly/logging/ObjectToString.h>

namespace folly {

template <bool IsInHeaderFile>
class XlogCategoryInfo;
class XlogFileScopeInfo;

/**
 * LogStreamProcessor receives a LogStream and logs it.
 *
 * This class is primarily intended to be used through the FB_LOG*() macros.
 * Its API is designed to support these macros, and is not designed for other
 * use.
 *
 * The operator&() method is used to trigger the logging.
 * This operator is used because it has lower precedence than <<, but higher
 * precedence than the ? ternary operator, allowing it to bind with the correct
 * precedence in the log macro implementations.
 */
class LogStreamProcessor {};

/**
 * LogStreamVoidify() is a helper class used in the FB_LOG() and XLOG() macros.
 *
 * It's only purpose is to provide an & operator overload that returns void.
 * This allows the log macros to expand roughly to:
 *
 *   (logEnabled) ? (void)0
 *                : LogStreamVoidify{} & LogStreamProcessor{}.stream() << "msg";
 *
 * This enables the right hand (':') side of the ternary ? expression to have a
 * void type, and allows various streaming operator expressions to be placed on
 * the right hand side of the expression.
 *
 * Operator & is used since it has higher precedence than ?:, but lower
 * precedence than <<.
 *
 * This class is templated on whether the log message is fatal so that the
 * operator& can be declared [[noreturn]] for fatal log messages.  This
 * prevents the compiler from complaining about functions that do not return a
 * value after a fatal log statement.
 */
template <bool Fatal>
class LogStreamVoidify {};

template <>
class LogStreamVoidify<true> {};

/**
 * logDisabledHelper() is invoked in FB_LOG() and XLOG() statements if the log
 * admittance check fails.
 *
 * This function exists solely to ensure that both sides of the log check are
 * marked [[noreturn]] for fatal log messages.  This allows the compiler to
 * recognize that the full statement is noreturn, preventing warnings about
 * missing return statements after fatal log messages.
 *
 * Unfortunately it does not appear possible to get the compiler to recognize
 * that the disabled side of the log statement should never be reached for
 * fatal messages.  Even if we make the check something like
 * `(isLogLevelFatal(level) || realCheck)`, where isLogLevelFatal() is
 * constexpr, this is not sufficient for gcc or clang to recognize that the
 * full expression is noreturn.
 *
 * Ideally this would just be a template function specialized on a boolean
 * IsFatal parameter.  Unfortunately this triggers a bug in clang, which does
 * not like differing noreturn behavior for different template instantiations.
 * Therefore we overload on integral_constant instead.
 *
 * clang-format also doesn't do a good job understanding this code and figuring
 * out how to format it.
 */
// clang-format off
inline void logDisabledHelper(std::false_type) noexcept {}
[[noreturn]] void logDisabledHelper(std::true_type) noexcept;
// clang-format on
} // namespace folly