cpp-common: add `logging.hpp` (`bt2c::Logger` and BT_CPPLOG*() macros)
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 14 Nov 2023 19:25:39 +0000 (14:25 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Thu, 14 Dec 2023 15:57:04 +0000 (10:57 -0500)
This new file contains the `bt2c::Logger` class of which an instance
contains:

* An actor: a self component class, a self component, a self message
  iterator, or a named module.

* A current logging level.

* A logging tag.

The class offers the logNoThrow(), logMemNoThrow(), logErrnoNoThrow(),
logErrorAndThrow(), logErrorAndRethrow(), logErrorErrnoAndThrow(), and
logErrorErrnoAndRethrow() method templates to log using a given level,
optionally append a cause to the error of the current thread using the
correct actor, and optionally throw or rethrow.

The methods above expect a format string and zero or more arguments to
be formatted with fmt::format(). There are also versions with `Str` in
the name which accept a single string.

All the logging methods are `const` so that you may log with a
`const bt2c::Logger`: they don't change any user-visible state.

Then, the various BT_CPPLOG*() macros call one of the log*() methods on
a logger instance with the current file name, function name, and line
number, forwarding the other arguments to the method. Those macros are
unfortunately needed for the file/function/line information, similar to
SPDLOG_LOGGER_INFO() vs. the info() method.

The macros of which the name ends with `_SPEC` accept a specific logger;
the other ones use the fixed `_mLogger` logger, which will be the case
most of the time (logging from a user component or message iterator).

Example:

    BT_CPPLOGE_APPEND_CAUSE_AND_THROW(Error,
                                      "Failed to add {0} items to `{1}` (expecting {0}, not {2})",
                                      expCount, containerName, count);

Internally, the logging methods fill `_mBuf` with fmt::format_to() and
pass the resulting string to some bt_log_write*() function. Argument
evaluation and formatting only happens if logging and/or error cause
appending will also happen.

Create a logger from another one with a different tag like this:

    MyThing::MyThing(const bt2c::Logger& parentLogger, ...) :
        _mLogger {parentLogger, "MY-THING"},
        ...

Make some code conditional to having some logging active for a given
level with the wouldLog*() methods (uses BT_LOG_ON_CUR_LVL()
internally):

    if (_mLogger.wouldLogD()) {
        // code which only exists to log
        BT_CPPLOGD(...);
    }

Note that this first version is not thread-safe (the underlying logging
framework is, but `_mBuf` isn't protected for a given logger).

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: Iacb4c26e42c868f27e3a85b9fe163acac870624f
Reviewed-on: https://review.lttng.org/c/babeltrace/+/11388
Reviewed-by: Simon Marchi <simon.marchi@efficios.com>
Tested-by: jenkins <jenkins@lttng.org>
CI-Build: Simon Marchi <simon.marchi@efficios.com>

src/Makefile.am
src/cpp-common/bt2c/logging.hpp [new file with mode: 0644]

index 04c960d624027dfde0c2bfa98a0d0e42a39760d1..debe1020f585c07113d5332c20779395ec92d8fd 100644 (file)
@@ -47,6 +47,7 @@ noinst_HEADERS = \
        cpp-common/bt2c/glib-up.hpp \
        cpp-common/bt2c/lib-str.hpp \
        cpp-common/bt2c/libc-up.hpp \
+       cpp-common/bt2c/logging.hpp \
        cpp-common/bt2c/read-fixed-len-int.hpp \
        cpp-common/bt2c/safe-ops.hpp \
        cpp-common/bt2c/std-int.hpp \
diff --git a/src/cpp-common/bt2c/logging.hpp b/src/cpp-common/bt2c/logging.hpp
new file mode 100644 (file)
index 0000000..893ee13
--- /dev/null
@@ -0,0 +1,971 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Philippe Proulx <pproulx@efficios.com>
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_BT2C_LOGGING_HPP
+#define BABELTRACE_CPP_COMMON_BT2C_LOGGING_HPP
+
+#include <cstring>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <babeltrace2/babeltrace.h>
+
+#include "common/assert.h"
+#include "cpp-common/bt2/private-query-executor.hpp"
+#include "cpp-common/bt2/self-component-class.hpp"
+#include "cpp-common/bt2/self-component-port.hpp"
+#include "cpp-common/bt2/self-message-iterator.hpp"
+#include "cpp-common/bt2s/optional.hpp"
+#include "cpp-common/vendor/fmt/core.h"
+#include "logging/log-api.h"
+
+namespace bt2c {
+
+/*
+ * A logger contains an actor (self component class, self component,
+ * self message iterator, or simple module name), a current logging
+ * level, and a logging tag.
+ *
+ * It offers the logNoThrow(), logMemNoThrow(), logErrnoNoThrow(),
+ * logErrorAndThrow(), logErrorAndRethrow(), logErrorErrnoAndThrow(),
+ * and logErrorErrnoAndRethrow() method templates to log using a given
+ * level, optionally append a cause to the error of the current thread
+ * using the correct actor, and optionally throw or rethrow.
+ *
+ * The methods above expect a format string and zero or more arguments
+ * to be formatted with fmt::format().
+ */
+class Logger final
+{
+public:
+    /* Available log levels */
+    enum class Level
+    {
+        TRACE = BT_LOG_TRACE,
+        DEBUG = BT_LOG_DEBUG,
+        INFO = BT_LOG_INFO,
+        WARNING = BT_LOG_WARNING,
+        ERROR = BT_LOG_ERROR,
+        FATAL = BT_LOG_FATAL,
+        NONE = BT_LOG_NONE,
+    };
+
+    /*
+     * Builds a logger from the self component class `selfCompCls` using
+     * the tag `tag` and the logging level of `privQueryExec`.
+     */
+    explicit Logger(const bt2::SelfComponentClass selfCompCls,
+                    const bt2::PrivateQueryExecutor privQueryExec, std::string tag) noexcept :
+        _mSelfCompCls {selfCompCls},
+        _mLevel {static_cast<Level>(privQueryExec.loggingLevel())}, _mTag {std::move(tag)}
+    {
+    }
+
+    /*
+     * Builds a logger from the self component `selfComp` using the tag
+     * `tag`.
+     */
+    explicit Logger(const bt2::SelfComponent selfComp, std::string tag) noexcept :
+        _mSelfComp {selfComp}, _mLevel {static_cast<Level>(selfComp.loggingLevel())}, _mTag {
+                                                                                          std::move(
+                                                                                              tag)}
+    {
+    }
+
+    /*
+     * Builds a logger from the self source component `selfComp` using
+     * the tag `tag`.
+     */
+    explicit Logger(const bt2::SelfSourceComponent selfComp, std::string tag) noexcept :
+        Logger {
+            bt2::SelfComponent {bt_self_component_source_as_self_component(selfComp.libObjPtr())},
+            std::move(tag)}
+    {
+    }
+
+    /*
+     * Builds a logger from the self filter component `selfComp` using
+     * the tag `tag`.
+     */
+    explicit Logger(const bt2::SelfFilterComponent selfComp, std::string tag) noexcept :
+        Logger {
+            bt2::SelfComponent {bt_self_component_filter_as_self_component(selfComp.libObjPtr())},
+            std::move(tag)}
+    {
+    }
+
+    /*
+     * Builds a logger from the self sink component `selfComp` using the
+     * tag `tag`.
+     */
+    explicit Logger(const bt2::SelfSinkComponent selfComp, std::string tag) noexcept :
+        Logger {bt2::SelfComponent {bt_self_component_sink_as_self_component(selfComp.libObjPtr())},
+                std::move(tag)}
+    {
+    }
+
+    /*
+     * Builds a logger from the self message iterator `selfMsgIter`
+     * using the tag `tag`.
+     */
+    explicit Logger(const bt2::SelfMessageIterator selfMsgIter, std::string tag) noexcept :
+        Logger {selfMsgIter.component(), std::move(tag)}
+    {
+        _mSelfMsgIter = selfMsgIter;
+    }
+
+    /*
+     * Builds a logger from the module named `moduleName` using the tag
+     * `tag` and logging level `logLevel`.
+     */
+    explicit Logger(std::string moduleName, std::string tag, const Level logLevel) noexcept :
+        _mModuleName {std::move(moduleName)}, _mLevel {logLevel}, _mTag {std::move(tag)}
+    {
+    }
+
+    /*
+     * Builds a logger from another logger `other` using the new tag
+     * `newTag`.
+     */
+    explicit Logger(const Logger& other, std::string newTag) :
+        _mSelfComp {other._mSelfComp}, _mSelfMsgIter {other._mSelfMsgIter},
+        _mModuleName {other._mModuleName}, _mLevel {other._mLevel}, _mTag {std::move(newTag)}
+    {
+    }
+
+    /*
+     * Current logging level.
+     */
+    Level level() const noexcept
+    {
+        return _mLevel;
+    }
+
+    /*
+     * Current logging level converted to a `bt_log_level` value.
+     *
+     * For legacy code.
+     */
+    bt_log_level cLevel() const noexcept
+    {
+        return static_cast<bt_log_level>(_mLevel);
+    }
+
+    /*
+     * Whether or not this logger would log at the level `level`.
+     */
+    bool wouldLog(const Level level) const noexcept
+    {
+        return BT_LOG_ON_CUR_LVL(static_cast<int>(level), static_cast<int>(_mLevel));
+    }
+
+    /*
+     * Whether or not this logger would log at the trace level.
+     */
+    bool wouldLogT() const noexcept
+    {
+        return this->wouldLog(Level::TRACE);
+    }
+
+    /*
+     * Whether or not this logger would log at the debug level.
+     */
+    bool wouldLogD() const noexcept
+    {
+        return this->wouldLog(Level::DEBUG);
+    }
+
+    /*
+     * Whether or not this logger would log at the info level.
+     */
+    bool wouldLogI() const noexcept
+    {
+        return this->wouldLog(Level::INFO);
+    }
+
+    /*
+     * Whether or not this logger would log at the warning level.
+     */
+    bool wouldLogW() const noexcept
+    {
+        return this->wouldLog(Level::WARNING);
+    }
+
+    /*
+     * Whether or not this logger would log at the error level.
+     */
+    bool wouldLogE() const noexcept
+    {
+        return this->wouldLog(Level::ERROR);
+    }
+
+    /*
+     * Whether or not this logger would log at the fatal level.
+     */
+    bool wouldLogF() const noexcept
+    {
+        return this->wouldLog(Level::FATAL);
+    }
+
+    /*
+     * Logging tag.
+     */
+    const std::string& tag() const noexcept
+    {
+        return _mTag;
+    }
+
+    /*
+     * Self component class actor, or `bt2s::nullopt` if none.
+     */
+    const bt2s::optional<bt2::SelfComponentClass>& selfCompCls() const noexcept
+    {
+        return _mSelfCompCls;
+    }
+
+    /*
+     * Self component actor, or `bt2s::nullopt` if none.
+     */
+    const bt2s::optional<bt2::SelfComponent>& selfComp() const noexcept
+    {
+        return _mSelfComp;
+    }
+
+    /*
+     * Self message iterator actor, or `bt2s::nullopt` if none.
+     */
+    const bt2s::optional<bt2::SelfMessageIterator>& selfMsgIter() const noexcept
+    {
+        return _mSelfMsgIter;
+    }
+
+    /*
+     * Name of module actor, or `bt2s::nullopt` if none.
+     */
+    const bt2s::optional<std::string>& moduleName() const noexcept
+    {
+        return _mModuleName;
+    }
+
+private:
+    struct _StdLogWriter final
+    {
+        static void write(const char * const fileName, const char * const funcName,
+                          const unsigned lineNo, const Level level, const char * const tag,
+                          const void *, unsigned int, const char *, const char * const msg) noexcept
+        {
+            bt_log_write(fileName, funcName, lineNo, static_cast<bt_log_level>(level), tag, msg);
+        }
+    };
+
+public:
+    /*
+     * Logs using the level `LevelV`.
+     *
+     * This method forwards `fmt` and `args` to fmt::format() to create
+     * the log message.
+     *
+     * If `AppendCauseV` is true, this method also appends a cause to
+     * the error of the current thread using the same message.
+     */
+    template <Level LevelV, bool AppendCauseV, typename... ArgTs>
+    void logNoThrow(const char * const fileName, const char * const funcName,
+                    const unsigned int lineNo, const char * const fmt, ArgTs&&...args) const
+    {
+        this->_logNoThrow<_StdLogWriter, LevelV, AppendCauseV>(
+            fileName, funcName, lineNo, nullptr, 0, nullptr, fmt, std::forward<ArgTs>(args)...);
+    }
+
+    /*
+     * Logs `msg` using the level `LevelV`.
+     *
+     * If `AppendCauseV` is true, this method also appends a cause to
+     * the error of the current thread using the same message.
+     */
+    template <Level LevelV, bool AppendCauseV>
+    void logStrNoThrow(const char * const fileName, const char * const funcName,
+                       const unsigned int lineNo, const char * const msg) const
+    {
+        this->_logStrNoThrow<_StdLogWriter, LevelV, AppendCauseV>(fileName, funcName, lineNo,
+                                                                  nullptr, 0, nullptr, msg);
+    }
+
+    /*
+     * Like logAndNoThrow() with the `Level::ERROR` level, but also
+     * throws a default-constructed instance of `ExcT`.
+     */
+    template <bool AppendCauseV, typename ExcT, typename... ArgTs>
+    [[noreturn]] void logErrorAndThrow(const char * const fileName, const char * const funcName,
+                                       const unsigned int lineNo, const char * const fmt,
+                                       ArgTs&&...args) const
+    {
+        this->logNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, fmt,
+                                                     std::forward<ArgTs>(args)...);
+        throw ExcT {};
+    }
+
+    /*
+     * Like logStrAndNoThrow() with the `Level::ERROR` level, but also
+     * throws a default-constructed instance of `ExcT`.
+     */
+    template <bool AppendCauseV, typename ExcT>
+    [[noreturn]] void logErrorStrAndThrow(const char * const fileName, const char * const funcName,
+                                          const unsigned int lineNo, const char * const msg) const
+    {
+        this->logStrNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, msg);
+        throw ExcT {};
+    }
+
+    /*
+     * Like logAndNoThrow() with the `Level::ERROR` level, but also
+     * rethrows.
+     */
+    template <bool AppendCauseV, typename... ArgTs>
+    [[noreturn]] void logErrorAndRethrow(const char * const fileName, const char * const funcName,
+                                         const unsigned int lineNo, const char * const fmt,
+                                         ArgTs&&...args) const
+    {
+        this->logNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, fmt,
+                                                     std::forward<ArgTs>(args)...);
+        throw;
+    }
+
+    /*
+     * Like logStrAndNoThrow() with the `Level::ERROR` level, but also
+     * rethrows.
+     */
+    template <bool AppendCauseV>
+    [[noreturn]] void logErrorStrAndRethrow(const char * const fileName,
+                                            const char * const funcName, const unsigned int lineNo,
+                                            const char * const msg) const
+    {
+        this->logStrNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, msg);
+        throw;
+    }
+
+private:
+    struct _ErrnoLogWriter final
+    {
+        static void write(const char * const fileName, const char * const funcName,
+                          const unsigned lineNo, const Level level, const char * const tag,
+                          const void *, unsigned int, const char * const initMsg,
+                          const char * const msg) noexcept
+        {
+            bt_log_write_errno(funcName, fileName, lineNo, static_cast<bt_log_level>(level), tag,
+                               initMsg, msg);
+        }
+    };
+
+public:
+    /*
+     * Logs the message of `errno` using the level `LevelV`.
+     *
+     * The log message starts with `initMsg`, is followed with the
+     * message for `errno`, and then with what fmt::format() creates
+     * given `fmt` and `args`.
+     *
+     * If `AppendCauseV` is true, this method also appends a cause to
+     * the error of the current thread using the same message.
+     */
+    template <Level LevelV, bool AppendCauseV, typename... ArgTs>
+    void logErrnoNoThrow(const char * const fileName, const char * const funcName,
+                         const unsigned int lineNo, const char * const initMsg,
+                         const char * const fmt, ArgTs&&...args) const
+    {
+        this->_logNoThrow<_ErrnoLogWriter, LevelV, AppendCauseV>(
+            fileName, funcName, lineNo, nullptr, 0, initMsg, fmt, std::forward<ArgTs>(args)...);
+    }
+
+    /*
+     * Logs the message of `errno` using the level `LevelV`.
+     *
+     * The log message starts with `initMsg`, is followed with the
+     * message for `errno`, and then with `msg`.
+     *
+     * If `AppendCauseV` is true, this method also appends a cause to
+     * the error of the current thread using the same message.
+     */
+    template <Level LevelV, bool AppendCauseV>
+    void logErrnoStrNoThrow(const char * const fileName, const char * const funcName,
+                            const unsigned int lineNo, const char * const initMsg,
+                            const char * const msg) const
+    {
+        this->_logStrNoThrow<_ErrnoLogWriter, LevelV, AppendCauseV>(fileName, funcName, lineNo,
+                                                                    nullptr, 0, initMsg, msg);
+    }
+
+    /*
+     * Like logErrnoNoThrow() with the `Level::ERROR` level, but also
+     * throws a default-constructed instance of `ExcT`.
+     */
+    template <bool AppendCauseV, typename ExcT, typename... ArgTs>
+    [[noreturn]] void logErrorErrnoAndThrow(const char * const fileName,
+                                            const char * const funcName, const unsigned int lineNo,
+                                            const char * const initMsg, const char * const fmt,
+                                            ArgTs&&...args) const
+    {
+        this->logErrnoNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, initMsg, fmt,
+                                                          std::forward<ArgTs>(args)...);
+        throw ExcT {};
+    }
+
+    /*
+     * Like logErrnoStrNoThrow() with the `Level::ERROR` level, but also
+     * throws a default-constructed instance of `ExcT`.
+     */
+    template <bool AppendCauseV, typename ExcT>
+    [[noreturn]] void
+    logErrorErrnoStrAndThrow(const char * const fileName, const char * const funcName,
+                             const unsigned int lineNo, const char * const initMsg,
+                             const char * const msg) const
+    {
+        this->logErrnoStrNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, initMsg,
+                                                             msg);
+        throw ExcT {};
+    }
+
+    /*
+     * Like logErrnoNoThrow() with the `Level::ERROR` level, but also
+     * rethrows.
+     */
+    template <bool AppendCauseV, typename... ArgTs>
+    [[noreturn]] void logErrorErrnoAndRethrow(const char * const fileName,
+                                              const char * const funcName,
+                                              const unsigned int lineNo, const char * const initMsg,
+                                              const char * const fmt, ArgTs&&...args) const
+    {
+        this->logErrnoNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, initMsg, fmt,
+                                                          std::forward<ArgTs>(args)...);
+        throw;
+    }
+
+    /*
+     * Like logErrnoStrNoThrow() with the `Level::ERROR` level, but also
+     * rethrows.
+     */
+    template <bool AppendCauseV>
+    [[noreturn]] void
+    logErrorErrnoStrAndRethrow(const char * const fileName, const char * const funcName,
+                               const unsigned int lineNo, const char * const initMsg,
+                               const char * const msg) const
+    {
+        this->logErrnoStrNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, initMsg,
+                                                             msg);
+        throw;
+    }
+
+private:
+    struct _MemLogWriter final
+    {
+        static void write(const char * const fileName, const char * const funcName,
+                          const unsigned lineNo, const Level level, const char * const tag,
+                          const void * const memData, const unsigned int memLen, const char *,
+                          const char * const msg) noexcept
+        {
+            bt_log_write_mem(funcName, fileName, lineNo, static_cast<bt_log_level>(level), tag,
+                             memData, memLen, msg);
+        }
+    };
+
+public:
+    /*
+     * Logs memory data using the level `LevelV`.
+     *
+     * This method forwards `fmt` and `args` to fmt::format() to create
+     * the log message.
+     */
+    template <Level LevelV, typename... ArgTs>
+    void logMemNoThrow(const char * const fileName, const char * const funcName,
+                       const unsigned int lineNo, const void * const memData,
+                       const unsigned int memLen, const char * const fmt, ArgTs&&...args) const
+    {
+        this->_logNoThrow<_MemLogWriter, LevelV, false>(fileName, funcName, lineNo, memData, memLen,
+                                                        nullptr, fmt, std::forward<ArgTs>(args)...);
+    }
+
+    /*
+     * Logs memory data using the level `LevelV`, starting with the
+     * message `msg`.
+     */
+    template <Level LevelV>
+    void logMemStrNoThrow(const char * const fileName, const char * const funcName,
+                          const unsigned int lineNo, const void * const memData,
+                          const unsigned int memLen, const char * const msg) const
+    {
+        this->_logStrNoThrow<_MemLogWriter, LevelV, false>(fileName, funcName, lineNo, memData,
+                                                           memLen, nullptr, msg);
+    }
+
+private:
+    /*
+     * Formats a log message with fmt::format() given `fmt` and `args`,
+     * and the forwards everything to _logStrNoThrow().
+     */
+    template <typename LogWriterT, Level LevelV, bool AppendCauseV, typename... ArgTs>
+    void _logNoThrow(const char * const fileName, const char * const funcName,
+                     const unsigned int lineNo, const void * const memData,
+                     const std::size_t memLen, const char * const initMsg, const char * const fmt,
+                     ArgTs&&...args) const
+    {
+        /* Only format arguments if logging or appending an error cause */
+        if (G_UNLIKELY(this->wouldLog(LevelV) || AppendCauseV)) {
+            /*
+             * Format arguments to our buffer (fmt::format_to() doesn't
+             * append a null character).
+             */
+            _mBuf.clear();
+            fmt::format_to(std::back_inserter(_mBuf), fmt, std::forward<ArgTs>(args)...);
+            _mBuf.push_back('\0');
+        }
+
+        this->_logStrNoThrow<LogWriterT, LevelV, AppendCauseV>(fileName, funcName, lineNo, memData,
+                                                               memLen, initMsg, _mBuf.data());
+    }
+
+    /*
+     * Logs `msg` using the level `LevelV`.
+     *
+     * Calls LogWriterT::write() to write the actual log.
+     *
+     * If `AppendCauseV` is true, this method also appends a cause to
+     * the error of the current thread using the same message.
+     */
+    template <typename LogWriterT, Level LevelV, bool AppendCauseV>
+    void _logStrNoThrow(const char * const fileName, const char * const funcName,
+                        const unsigned int lineNo, const void * const memData,
+                        const std::size_t memLen, const char * const initMsg,
+                        const char * const msg) const
+    {
+        /* Log if needed */
+        if (this->wouldLog(LevelV)) {
+            LogWriterT::write(fileName, funcName, lineNo, LevelV, _mTag.data(), memData, memLen,
+                              initMsg, msg);
+        }
+
+        /* Append an error cause if needed */
+        if (AppendCauseV) {
+            if (_mSelfMsgIter) {
+                bt_current_thread_error_append_cause_from_message_iterator(
+                    _mSelfMsgIter->libObjPtr(), fileName, lineNo, "%s", _mBuf.data());
+            } else if (_mSelfComp) {
+                bt_current_thread_error_append_cause_from_component(
+                    _mSelfComp->libObjPtr(), fileName, lineNo, "%s", _mBuf.data());
+            } else if (_mSelfCompCls) {
+                bt_current_thread_error_append_cause_from_component_class(
+                    _mSelfCompCls->libObjPtr(), fileName, lineNo, "%s", _mBuf.data());
+            } else {
+                BT_ASSERT_DBG(_mModuleName);
+                bt_current_thread_error_append_cause_from_unknown(_mModuleName->data(), fileName,
+                                                                  lineNo, "%s", _mBuf.data());
+            }
+        }
+    }
+
+    /* At least one of the following four members has a value */
+    bt2s::optional<bt2::SelfComponentClass> _mSelfCompCls;
+    bt2s::optional<bt2::SelfComponent> _mSelfComp;
+    bt2s::optional<bt2::SelfMessageIterator> _mSelfMsgIter;
+    bt2s::optional<std::string> _mModuleName;
+
+    /* Current logging level */
+    Level _mLevel;
+
+    /* Logging tag */
+    std::string _mTag;
+
+    /* Formatting buffer */
+    mutable std::vector<char> _mBuf;
+};
+
+} /* namespace bt2c */
+
+/* Internal: default logger name */
+#define _BT_CPPLOG_DEF_LOGGER _mLogger
+
+/*
+ * Calls logNoThrow() on `_logger` to log using the level `_lvl` without
+ * appending nor throwing.
+ */
+#define BT_CPPLOG_EX(_lvl, _logger, _fmt, ...)                                                     \
+    do {                                                                                           \
+        if (G_UNLIKELY((_logger).wouldLog(_lvl))) {                                                \
+            (_logger).logNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_fmt),              \
+                                                ##__VA_ARGS__);                                    \
+        }                                                                                          \
+    } while (0)
+
+/*
+ * BT_CPPLOG_EX() with specific logging levels.
+ */
+#define BT_CPPLOGT_SPEC(_logger, _fmt, ...)                                                        \
+    BT_CPPLOG_EX(bt2c::Logger::Level::TRACE, (_logger), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD_SPEC(_logger, _fmt, ...)                                                        \
+    BT_CPPLOG_EX(bt2c::Logger::Level::DEBUG, (_logger), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI_SPEC(_logger, _fmt, ...)                                                        \
+    BT_CPPLOG_EX(bt2c::Logger::Level::INFO, (_logger), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW_SPEC(_logger, _fmt, ...)                                                        \
+    BT_CPPLOG_EX(bt2c::Logger::Level::WARNING, (_logger), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_SPEC(_logger, _fmt, ...)                                                        \
+    BT_CPPLOG_EX(bt2c::Logger::Level::ERROR, (_logger), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF_SPEC(_logger, _fmt, ...)                                                        \
+    BT_CPPLOG_EX(bt2c::Logger::Level::FATAL, (_logger), (_fmt), ##__VA_ARGS__)
+
+/*
+ * BT_CPPLOG_EX() with specific logging levels and using the default
+ * logger.
+ */
+#define BT_CPPLOGT(_fmt, ...) BT_CPPLOGT_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD(_fmt, ...) BT_CPPLOGD_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI(_fmt, ...) BT_CPPLOGI_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW(_fmt, ...) BT_CPPLOGW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE(_fmt, ...) BT_CPPLOGE_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF(_fmt, ...) BT_CPPLOGF_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
+
+/*
+ * Calls logStrNoThrow() on `_logger` to log using the level `_lvl`
+ * without appending nor throwing.
+ */
+#define BT_CPPLOG_STR_EX(_lvl, _logger, _msg)                                                      \
+    (_logger).logStrNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_msg))
+
+/*
+ * BT_CPPLOG_STR_EX() with specific logging levels.
+ */
+#define BT_CPPLOGT_STR_SPEC(_logger, _msg)                                                         \
+    BT_CPPLOG_STR_EX(bt2c::Logger::Level::TRACE, (_logger), (_msg))
+#define BT_CPPLOGD_STR_SPEC(_logger, _msg)                                                         \
+    BT_CPPLOG_STR_EX(bt2c::Logger::Level::DEBUG, (_logger), (_msg))
+#define BT_CPPLOGI_STR_SPEC(_logger, _msg)                                                         \
+    BT_CPPLOG_STR_EX(bt2c::Logger::Level::INFO, (_logger), (_msg))
+#define BT_CPPLOGW_STR_SPEC(_logger, _msg)                                                         \
+    BT_CPPLOG_STR_EX(bt2c::Logger::Level::WARNING, (_logger), (_msg))
+#define BT_CPPLOGE_STR_SPEC(_logger, _msg)                                                         \
+    BT_CPPLOG_STR_EX(bt2c::Logger::Level::ERROR, (_logger), (_msg))
+#define BT_CPPLOGF_STR_SPEC(_logger, _msg)                                                         \
+    BT_CPPLOG_STR_EX(bt2c::Logger::Level::FATAL, (_logger), (_msg))
+
+/*
+ * BT_CPPLOG_STR_EX() with specific logging levels and using the default
+ * logger.
+ */
+#define BT_CPPLOGT_STR(_msg) BT_CPPLOGT_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
+#define BT_CPPLOGD_STR(_msg) BT_CPPLOGD_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
+#define BT_CPPLOGI_STR(_msg) BT_CPPLOGI_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
+#define BT_CPPLOGW_STR(_msg) BT_CPPLOGW_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
+#define BT_CPPLOGE_STR(_msg) BT_CPPLOGE_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
+#define BT_CPPLOGF_STR(_msg) BT_CPPLOGF_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
+
+/*
+ * Calls logMemNoThrow() on `_logger` to log using the level `_lvl`
+ * without appending nor throwing.
+ */
+#define BT_CPPLOG_MEM_EX(_lvl, _logger, _mem_data, _mem_len, _fmt, ...)                            \
+    do {                                                                                           \
+        if (G_UNLIKELY((_logger).wouldLog(_lvl))) {                                                \
+            (_logger).logMemNoThrow<(_lvl)>(__FILE__, __func__, __LINE__, (_mem_data), (_mem_len), \
+                                            (_fmt), ##__VA_ARGS__);                                \
+        }                                                                                          \
+    } while (0)
+
+/*
+ * BT_CPPLOG_MEM_EX() with specific logging levels.
+ */
+#define BT_CPPLOGT_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::TRACE, (_logger), (_mem_data), (_mem_len), (_fmt),       \
+                     ##__VA_ARGS__)
+#define BT_CPPLOGD_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::DEBUG, (_logger), (_mem_data), (_mem_len), (_fmt),       \
+                     ##__VA_ARGS__)
+#define BT_CPPLOGI_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::INFO, (_logger), (_mem_data), (_mem_len), (_fmt),        \
+                     ##__VA_ARGS__)
+#define BT_CPPLOGW_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::WARNING, (_logger), (_mem_data), (_mem_len), (_fmt),     \
+                     ##__VA_ARGS__)
+#define BT_CPPLOGE_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::ERROR, (_logger), (_mem_data), (_mem_len), (_fmt),       \
+                     ##__VA_ARGS__)
+#define BT_CPPLOGF_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::FATAL, (_logger), (_mem_data), (_mem_len), (_fmt),       \
+                     ##__VA_ARGS__)
+
+/*
+ * BT_CPPLOG_MEM_EX() with specific logging levels and using the default
+ * logger.
+ */
+#define BT_CPPLOGT_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
+    BT_CPPLOGT_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
+    BT_CPPLOGD_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
+    BT_CPPLOGI_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
+    BT_CPPLOGW_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
+    BT_CPPLOGE_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
+    BT_CPPLOGF_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
+
+/*
+ * Calls logMemStrNoThrow() on `_logger` to log using the level `_lvl`
+ * without appending nor throwing.
+ */
+#define BT_CPPLOG_MEM_STR_EX(_lvl, _logger, _mem_data, _mem_len, _msg)                             \
+    (_logger).logMemStrNoThrow<(_lvl)>(__FILE__, __func__, __LINE__, (_mem_data), (_mem_len),      \
+                                       (_msg))
+
+/*
+ * BT_CPPLOG_MEM_STR_EX() with specific logging levels.
+ */
+#define BT_CPPLOGT_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
+    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::TRACE, (_logger), (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGD_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
+    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::DEBUG, (_logger), (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGI_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
+    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::INFO, (_logger), (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGW_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
+    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::WARNING, (_logger), (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGE_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
+    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::ERROR, (_logger), (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGF_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
+    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::FATAL, (_logger), (_mem_data), (_mem_len), (_msg))
+
+/*
+ * BT_CPPLOG_MEM_STR_EX() with specific logging levels and using the
+ * default logger.
+ */
+#define BT_CPPLOGT_MEM_STR(_mem_data, _mem_len, _msg)                                              \
+    BT_CPPLOGT_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGD_MEM_STR(_mem_data, _mem_len, _msg)                                              \
+    BT_CPPLOGD_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGI_MEM_STR(_mem_data, _mem_len, _msg)                                              \
+    BT_CPPLOGI_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGW_MEM_STR(_mem_data, _mem_len, _msg)                                              \
+    BT_CPPLOGW_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGE_MEM_STR(_mem_data, _mem_len, _msg)                                              \
+    BT_CPPLOGE_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGF_MEM_STR(_mem_data, _mem_len, _msg)                                              \
+    BT_CPPLOGF_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
+
+/*
+ * Calls logErrnoNoThrow() on `_logger` to log using the level `_lvl`
+ * and initial message `_init_msg` without appending nor throwing.
+ */
+#define BT_CPPLOG_ERRNO_EX(_lvl, _logger, _init_msg, _fmt, ...)                                    \
+    do {                                                                                           \
+        if (G_UNLIKELY((_logger).wouldLog(_lvl))) {                                                \
+            (_logger).logErrnoNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_init_msg),    \
+                                                     (_fmt), ##__VA_ARGS__);                       \
+        }                                                                                          \
+    } while (0)
+
+/*
+ * BT_CPPLOG_ERRNO_EX() with specific logging levels.
+ */
+#define BT_CPPLOGT_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::TRACE, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::DEBUG, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::INFO, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::WARNING, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::ERROR, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::FATAL, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
+
+/*
+ * BT_CPPLOG_ERRNO_EX() with specific logging levels and using the
+ * default logger.
+ */
+#define BT_CPPLOGT_ERRNO(_init_msg, _fmt, ...)                                                     \
+    BT_CPPLOGT_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD_ERRNO(_init_msg, _fmt, ...)                                                     \
+    BT_CPPLOGD_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI_ERRNO(_init_msg, _fmt, ...)                                                     \
+    BT_CPPLOGI_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW_ERRNO(_init_msg, _fmt, ...)                                                     \
+    BT_CPPLOGW_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_ERRNO(_init_msg, _fmt, ...)                                                     \
+    BT_CPPLOGE_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF_ERRNO(_init_msg, _fmt, ...)                                                     \
+    BT_CPPLOGF_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
+
+/*
+ * Calls logErrnoStrNoThrow() on `_logger` to log using the level `_lvl`
+ * and initial message `_init_msg` without appending nor throwing.
+ */
+#define BT_CPPLOG_ERRNO_STR_EX(_lvl, _logger, _init_msg, _msg)                                     \
+    (_logger).logErrnoStrNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_init_msg), (_msg))
+
+/*
+ * BT_CPPLOG_ERRNO_STR_EX() with specific logging levels.
+ */
+#define BT_CPPLOGT_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
+    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::TRACE, (_logger), (_init_msg), (_msg))
+#define BT_CPPLOGD_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
+    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::DEBUG, (_logger), (_init_msg), (_msg))
+#define BT_CPPLOGI_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
+    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::INFO, (_logger), (_init_msg), (_msg))
+#define BT_CPPLOGW_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
+    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::WARNING, (_logger), (_init_msg), (_msg))
+#define BT_CPPLOGE_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
+    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::ERROR, (_logger), (_init_msg), (_msg))
+#define BT_CPPLOGF_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
+    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::FATAL, (_logger), (_init_msg), (_msg))
+
+/*
+ * BT_CPPLOG_ERRNO_STR_EX() with specific logging levels and using the
+ * default logger.
+ */
+#define BT_CPPLOGT_ERRNO_STR(_init_msg, _msg)                                                      \
+    BT_CPPLOGT_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
+#define BT_CPPLOGD_ERRNO_STR(_init_msg, _msg)                                                      \
+    BT_CPPLOGD_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
+#define BT_CPPLOGI_ERRNO_STR(_init_msg, _msg)                                                      \
+    BT_CPPLOGI_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
+#define BT_CPPLOGW_ERRNO_STR(_init_msg, _msg)                                                      \
+    BT_CPPLOGW_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
+#define BT_CPPLOGE_ERRNO_STR(_init_msg, _msg)                                                      \
+    BT_CPPLOGE_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
+#define BT_CPPLOGF_ERRNO_STR(_init_msg, _msg)                                                      \
+    BT_CPPLOGF_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
+
+/*
+ * Calls logErrorAndThrow() on `_logger` to log an error, append a cause
+ * to the error of the current thread, and throw an instance of
+ * `_exc_cls`.
+ */
+#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _fmt, ...)                       \
+    (_logger).logErrorAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__)
+
+/*
+ * Calls logErrorAndThrow() on `_logger` to log an error, append a cause
+ * to the error of the current thread, and throw an instance of
+ * `_exc_cls`.
+ */
+#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _fmt, ...)                       \
+    (_logger).logErrorAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__)
+
+/*
+ * BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC() using the default logger.
+ */
+#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW(_exc_cls, _fmt, ...)                                     \
+    BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _exc_cls, (_fmt), ##__VA_ARGS__)
+
+/*
+ * Calls logErrorStrAndThrow() on `_logger` to log an error, append a
+ * cause to the error of the current thread, and throw an instance of
+ * `_exc_cls`.
+ */
+#define BT_CPPLOGE_STR_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _msg)                        \
+    (_logger).logErrorStrAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_msg))
+
+/*
+ * BT_CPPLOGE_STR_APPEND_CAUSE_AND_THROW_SPEC() using the default
+ * logger.
+ */
+#define BT_CPPLOGE_STR_APPEND_CAUSE_AND_THROW(_exc_cls, _msg)                                      \
+    BT_CPPLOGE_STR_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _exc_cls, (_msg))
+
+/*
+ * Calls logErrorAndRethrow() on `_logger` to log an error, append a
+ * cause to the error of the current thread, and throw an instance of
+ * `_exc_cls`.
+ */
+#define BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _fmt, ...)                               \
+    (_logger).logErrorAndRethrow<true>(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__)
+
+/*
+ * BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW_SPEC() using the default logger.
+ */
+#define BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW(_fmt, ...)                                             \
+    BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
+
+/*
+ * Calls logErrorStrAndRethrow() on `_logger` to log an error, append a
+ * cause to the error of the current thread, and throw an instance of
+ * `_exc_cls`.
+ */
+#define BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _msg)                                \
+    (_logger).logErrorStrAndRethrow<true>(__FILE__, __func__, __LINE__, (_msg))
+
+/*
+ * BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW_SPEC() using the default
+ * logger.
+ */
+#define BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW(_msg)                                              \
+    BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
+
+/*
+ * Calls logErrorErrnoAndThrow() on `_logger` to log an error, append a
+ * cause to the error of the current thread, and throw an instance of
+ * `_exc_cls`.
+ */
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _init_msg, _fmt, ...)      \
+    (_logger).logErrorErrnoAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_init_msg),     \
+                                                    (_fmt), ##__VA_ARGS__)
+
+/*
+ * BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC() using the default
+ * logger.
+ */
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW(_exc_cls, _init_msg, _fmt, ...)                    \
+    BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _exc_cls, (_init_msg),     \
+                                                 (_fmt), ##__VA_ARGS__)
+
+/*
+ * Calls logErrorErrnoStrAndThrow() on `_logger` to log an error, append
+ * a cause to the error of the current thread, and throw an instance of
+ * `_exc_cls`.
+ */
+#define BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _init_msg, _msg)       \
+    (_logger).logErrorErrnoStrAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_init_msg),  \
+                                                       (_msg))
+
+/*
+ * BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_THROW_SPEC() using the default
+ * logger.
+ */
+#define BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_THROW(_exc_cls, _init_msg, _msg)                     \
+    BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _exc_cls, (_init_msg), \
+                                                     (_msg))
+
+/*
+ * Calls logErrorErrnoAndRethrow() on `_logger` to log an error, append
+ * a cause to the error of the current thread, and throw an instance of
+ * `_exc_cls`.
+ */
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _init_msg, _fmt, ...)              \
+    (_logger).logErrorErrnoAndRethrow<true>(__FILE__, __func__, __LINE__, (_init_msg), (_fmt),     \
+                                            ##__VA_ARGS__)
+
+/*
+ * BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC() using the default
+ * logger.
+ */
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW(_init_msg, _fmt, ...)                            \
+    BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt),     \
+                                                   ##__VA_ARGS__)
+
+/*
+ * Calls logErrorErrnoStrAndRethrow() on `_logger` to log an error,
+ * append a cause to the error of the current thread, and throw an
+ * instance of `_exc_cls`.
+ */
+#define BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _init_msg, _msg)               \
+    (_logger).logErrorErrnoStrAndRethrow<true>(__FILE__, __func__, __LINE__, (_init_msg), (_msg))
+
+/*
+ * BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_RETHROW_SPEC() using the
+ * default logger.
+ */
+#define BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_RETHROW(_init_msg, _msg)                             \
+    BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
+
+#endif /* BABELTRACE_CPP_COMMON_BT2C_LOGGING_HPP */
This page took 0.035119 seconds and 4 git commands to generate.