logging – Registrar class (C ++)

I wrote a simple registrar class for my project. Some key points:

  • The interface is very inspired by the Java log libraries (collectors / setters can say that I am a Java programmer). In particular, I am using the printf style functions instead of the std :: ostream style, which I don't like very much.
  • Verifying is a macro similar to asserting, but instead of aborting, it throws std :: logic_error and cannot be disabled with NDEBUG.
  • Heavy work is done by Handler, which I did not include here because it is quite code and not finished.

Without further ado, here is log.hpp

#pragma once

#include "verify.hpp"

#include 
#include 
#include 

namespace bran {
    enum class log_severity : unsigned {
        INHERIT,
        TRACE,
        DEBUG,
        INFO,
        WARN,
        ERROR,
        FATAL
    };

    std::ostream& operator<<(std::ostream& out, log_severity severity);

    template
    class basic_logger;

    template
    void swap(basic_logger& a, basic_logger& b) noexcept;

    template
    class basic_logger {
    public:
        explicit basic_logger(const std::string& name, basic_logger* parent, Handler* handler);
        explicit basic_logger(const std::string& name, basic_logger& parent);
        explicit basic_logger(const std::string& name, Handler& handler);

        basic_logger(basic_logger&& l) noexcept;
        basic_logger(const basic_logger&) = delete;

        ~basic_logger() = default;

        basic_logger& operator=(basic_logger l) noexcept;

        ((nodiscard)) inline std::string get_name() const noexcept;

        void set_threshold(log_severity threshold);
        ((nodiscard)) inline log_severity get_threshold() const noexcept;

        void set_handler(Handler* handler);
        ((nodiscard)) inline Handler* get_handler() const noexcept;

        void set_parent(basic_logger* parent);
        ((nodiscard)) inline basic_logger* get_parent() const noexcept;

        ((nodiscard)) inline bool is_trace() const noexcept;
        ((nodiscard)) inline bool is_debug() const noexcept;
        ((nodiscard)) inline bool is_info() const noexcept;
        ((nodiscard)) inline bool is_warn() const noexcept;
        ((nodiscard)) inline bool is_error() const noexcept;

        template
        inline void trace(const std::string& message, T... args);
        template
        inline void debug(const std::string& message, T... args);
        template
        inline void info(const std::string& message, T... args);
        template
        inline void warn(const std::string& message, T... args);
        template
        inline void error(const std::string& message, T... args);
        template
        inline void fatal(const std::string& message, T... args);

    private:
        std::string name;
        log_severity threshold;
        basic_logger* parent;
        Handler* handler;

        template
        inline void log(log_severity severity, const std::string& message, T... args);

    public:
        friend void swap(basic_logger& a, basic_logger& b) noexcept;
    };
}

template
bran::basic_logger::basic_logger(const std::string& name, basic_logger* parent, Handler* handler)
        : name{name}, parent{parent}, handler{handler} {
    verify(!name.empty() && (parent != nullptr || handler != nullptr));
    if (parent != nullptr) {
        threshold = log_severity::INHERIT;
    } else {
        threshold = log_severity::TRACE;
    }
}

template
bran::basic_logger::basic_logger(const std::string& name, basic_logger& parent)
        : basic_logger{name, &parent, nullptr} {
}

template
bran::basic_logger::basic_logger(const std::string& name, Handler& handler)
        : basic_logger{name, nullptr, &handler} {
}

template
bran::basic_logger::basic_logger(basic_logger&& l) noexcept {
    swap(*this, l);
}

template
bran::basic_logger& bran::basic_logger::operator=(basic_logger l) noexcept {
    swap(*this, l);
    return *this;
}

template
std::string bran::basic_logger::get_name() const noexcept {
    return name;
}

template
void bran::basic_logger::set_threshold(log_severity threshold) {
    verify(threshold != log_severity::INHERIT || parent != nullptr);
    this->threshold = threshold;
}

template
bran::log_severity bran::basic_logger::get_threshold() const noexcept {
    assert(threshold != log_severity::INHERIT || parent != nullptr);
    return threshold == log_severity::INHERIT ? parent->get_threshold() : threshold;
}

template
void bran::basic_logger::set_handler(Handler* handler) {
    verify(handler != nullptr || parent != nullptr);
    this->handler = handler;
}

template
Handler* bran::basic_logger::get_handler() const noexcept {
    assert(handler != nullptr || parent != nullptr);
    return handler == nullptr ? parent->get_handler() : handler;
}

template
void bran::basic_logger::set_parent(basic_logger* parent) {
    verify(parent != nullptr || (handler != nullptr && threshold != log_severity::INHERIT));
    this->parent = parent;
}

template
bran::basic_logger* bran::basic_logger::get_parent() const noexcept {
    return parent;
}

template
bool bran::basic_logger::is_trace() const noexcept {
    return get_threshold() <= log_severity::TRACE;
}

template
bool bran::basic_logger::is_debug() const noexcept {
    return get_threshold() <= log_severity::DEBUG;
}

template
bool bran::basic_logger::is_info() const noexcept {
    return get_threshold() <= log_severity::INFO;
}

template
bool bran::basic_logger::is_warn() const noexcept {
    return get_threshold() <= log_severity::WARN;
}

template
bool bran::basic_logger::is_error() const noexcept {
    return get_threshold() <= log_severity::ERROR;
}

template
template
void bran::basic_logger::trace(const std::string& message, T... args) {
    log(log_severity::TRACE, message, args...);
}

template
template
void bran::basic_logger::debug(const std::string& message, T... args) {
    log(log_severity::DEBUG, message, args...);
}

template
template
void bran::basic_logger::info(const std::string& message, T... args) {
    log(log_severity::INFO, message, args...);
}

template
template
void bran::basic_logger::warn(const std::string& message, T... args) {
    log(log_severity::WARN, message, args...);
}

template
template
void bran::basic_logger::error(const std::string& message, T... args) {
    log(log_severity::ERROR, message, args...);
}

template
template
void bran::basic_logger::fatal(const std::string& message, T... args) {
    log(log_severity::FATAL, message, args...);
}

template
template
void bran::basic_logger::log(log_severity severity, const std::string& message, T... args) {
    if (get_threshold() > severity) {
        return;
    }

    get_handler()->log(*this, severity, message, args...);
}

template
void bran::swap(basic_logger& a, basic_logger& b) noexcept {
    using std::swap;

    swap(a.name, b.name);
    swap(a.threshold, b.threshold);
    swap(a.parent, b.parent);
    swap(a.handler, b.handler);
}

And the insignificant log.cpp

#include "log.hpp"

std::ostream& bran::operator<<(std::ostream& out, bran::log_severity severity) {
    static const std::string SEVERITY_NAMES() = {"INHERIT", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
    static const size_t SEVERITY_COUNT = sizeof(SEVERITY_NAMES) / sizeof(SEVERITY_NAMES(0));

    auto index = static_cast(severity);
    assert(index < SEVERITY_COUNT);

    return out << SEVERITY_NAMES(index);
}