Make RPM package 创建 RPM 包

Make RPM package 创建 RPM 包

…NOT recommended, maybe better :point_right: DEB/APT … see


  • Example on centos7 18.04.
  • 直接在 源码目录 / GIT 仓库创建
  • 没有 tarball — 没必要
  • 没有 configure — 使用 CMAKE
  • 创建的包不安装到 /usr/...
  • 创建包的根目录不是 ~/... — 就在当前工程下面
  • 此外对于 APP 包还有 strippost install 等需要处理
  • 不要使用 root 用户, 普通用户创建权限足够了

Install building tools

sudo yum install rpm-build
sudo yum install rpmdevtools

创建使用的配置文件 .spec 示例

详见:

## MY_PROJ_NAME.desc
# topdir is here, NOT ~/...
%define _topdir %(pwd)/rpmbuild
# %(pwd)/MY_SRC_DIR
%define srcdir %(pwd)/yuiwongcppbase
# MY_PREFIX
%define prefix opt/lib/yuiwongcppbase
%define builddir %{srcdir}/build
Name:         libyuiwongcppbase-devel
Version:      1.1.1
Release:      1%{?dist}
# MY_SHORT_DESCRIPTION
Summary:      C++ common library.

Group:        yuiwong.org
License:      LGPL-3.0
URL:          https://yuiwong.org/gitlab/cpp/cppbase
Source0:      gitsrc

#BuildRequires:
#Requires:

%description
# MY_DESCRIPTION
C++ common library.

%prep
# NOT xf tarball
#%setup -q

%build
cd %{srcdir}
rm -rf build
mkdir -p build
cd build
echo %{buildroot}
cmake .. \
  -DCMAKE_INSTALL_PREFIX=%{buildroot}/%{prefix} \
  -DENABLETEST=0 \
  -DEIGEN3=/opt/lib/eigen3 \
  -Dboost=/usr
echo "exit 0" > configure
chmod 700 configure
%configure
#make %{?_smp_mflags}
#make

%install
#make install DESTDIR=%{buildroot}
cd %{builddir}
make install
cd -

%files
/%{prefix}
%doc

%clean
rm -rf %{buildroot}/%{prefix}
rm -rf %{builddir}

%changelog

Make

rpmbuild -bb rpmbuild/yuiwongcppbase.spec

一个简单实用的 C++ logger

一个简单实用的 C++ logger

  • Log4cxx like, more powerful and slight stream logger
  • Thread-safe and with max log size limit(deque old logs when full)
  • Full ans esay set...()interfaces
  • Logging hook callback and tag(name) filter support
  • Dynamic log level
  • Friendly and source tarceable logger helper support

Full code, example and release package see:

Part code:

constexpr char const* kPrimaryDefaultLogFile = "logger.log";
constexpr uint32_t kMinLogSize = 8192;
/// 256 MB / 128 MB
constexpr uint32_t kDefaultLogSize = sizeof(long) * 32 * 1024 * 1024;
struct Logger {
    /// Output type
    enum Output: uint32_t {
        CoutOrCerr = 0x1,
        File       = 0x2,
        Both       = 0x3,
    };
    /// If 0 => when get logger not change current or default
    using Outputs = Flags<Output>;
    /// Callback when set when append
    using AppendCallback = std::function<void(
        std::string const& name,
        LogLevel const& logLevel,
        std::string const& msg)>;
    /// Dtor to auto finish logger
    virtual ~Logger() noexcept;
    // Global configs
    /// Set default logger, set only when path not empty
    static inline void setDefaultLogger(std::string const& path) noexcept;
    static inline std::string getDefaultLogger() noexcept;
    /**
     * Get a Logger instance
     * @param spinOnceLogLevel If not Unchange, will be use once
     * @param path Logger filename, if empty then will get a default Logger
     * @param outputs output config, used when create logger, if 0 then use
     * default or current exists
     */
    static Logger& getLogger(
        LogLevel const& spinOnceLogLevel = LogLevel::Unchange,
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    static inline Logger& getFatal(
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    static inline Logger& getError(
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    static inline Logger& getWarning(
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    static inline Logger& getNote(
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    static inline Logger& getInfo(
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    static inline Logger& getTrace(
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    static inline Logger& getDebug(
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    static inline Logger& getDetail(
        std::string const& path = "",
        Outputs const& outputs = Outputs{}) noexcept;
    /// Release a logger
    static void releaseLogger(std::string const& file) noexcept;
    // Instance config
    void setLogLevel(LogLevel const& logLevel) noexcept;
    /// Toggle log level
    LogLevel toggleLogLevel() noexcept;
    /**
     * Set max log size
     * - If < 0 keep current max
     * - If < kMinLogSize use kMinLogSize
     */
    void setMaxSize(int32_t const maxSize) noexcept;
    inline void setOutputs(Outputs const& o) noexcept;
    inline void setAppendCallback(AppendCallback const& ac) noexcept;
    inline void enableIdx(bool const enable) noexcept;
    inline void enableTid(bool const enable) noexcept;
    /// @note copy
    std::set<std::string> getAcNameFilters() const noexcept;
    bool hasAcNameFilter(std::string const& acNameFilter) const noexcept;
    bool addAcNameFilter(std::string const& acNameFilter) noexcept;
    bool removeAcNameFilter(std::string const& acNameFilter) noexcept;
    void clearAcNameFilters() noexcept;
    /// Limit log size
    void shrinkToFit() noexcept;
    /// Check if log instance valid
    inline operator bool() const noexcept;
    /// @note Only check log level
    inline bool isLogable(LogLevel const& ll) const noexcept;
    inline LogLevel getLogLevel() const noexcept;
    /**
     * Reset logger file
     * @note
     * - When param valid => will always open or reopen
     * - When param invalid => will use default or not-reopen
     */
    int64_t reset(bool const trunc = false) noexcept;
    /// Append name + file + line + msg
    int append(
        char const* const name,
        char const* const file,
        int const line,
        std::string const& msg,
        LogLevel const& logLevel) noexcept;
    /// Append a string msg
    int append(std::string const& msg, LogLevel const& logLevel) noexcept;
    // Logging methods
    // f
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& f(T const& msg)
        noexcept;
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& f(
        std::string const& name, T const& msg) noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& f(T const& msg)
        noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& f(
        std::string const& name, T const& msg) noexcept;
    template<uint32_t sz> Logger& f(const char(&msg)[sz]) noexcept;
    template<uint32_t sz> Logger& f(
        std::string const& name, const char(&msg)[sz]) noexcept;
    // e
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& e(T const& msg)
        noexcept;
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& e(
        std::string const& name, T const& msg) noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& e(T const& msg)
        noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& e(
        std::string const& name, T const& msg) noexcept;
    template<uint32_t sz> Logger& e(char const(&msg)[sz]) noexcept;
    template<uint32_t sz> Logger& e(
        std::string const& name, char const(&msg)[sz]) noexcept;
    // w
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& w(T const& msg)
        noexcept;
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& w(
        std::string const& name, T const& msg) noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& w(T const& msg)
        noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& w(
        std::string const& name, T const& msg) noexcept;
    template<uint32_t sz> Logger& w(char const(&msg)[sz]) noexcept;
    template<uint32_t sz> Logger& w(
        std::string const& name, char const(&msg)[sz]) noexcept;
    // n
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& n(T const& msg)
        noexcept;
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& n(
        std::string const& name, T const& msg) noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& n(T const& msg)
        noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& n(
        std::string const& name, T const& msg) noexcept;
    template<uint32_t sz> Logger& n(char const(&msg)[sz]) noexcept;
    template<uint32_t sz> Logger& n(
        std::string const& name, char const(&msg)[sz]) noexcept;
    // i
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& i(T const& msg)
        noexcept;
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& i(
        std::string const& name, T const& msg) noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& i(T const& msg)
        noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& i(
        std::string const& name, T const& msg) noexcept;
    template<uint32_t sz> Logger& i(char const(&msg)[sz]) noexcept;
    template<uint32_t sz> Logger& i(
        std::string const& name, char const(&msg)[sz]) noexcept;
    // d
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& d(T const& msg)
        noexcept;
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& d(
        std::string const& name, T const& msg) noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& d(T const& msg)
        noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& d(
        std::string const& name, T const& msg) noexcept;
    template<uint32_t sz> Logger& d(char const(&msg)[sz]) noexcept;
    template<uint32_t sz> Logger& d(
        std::string const& name, char const(&msg)[sz]) noexcept;
    // <<
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& operator<<(
        T const& msg) noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& operator<<(
        T const& msg) noexcept;
    template<uint32_t sz>
    Logger& operator<<(char const(&msg)[sz]) noexcept;
    // ,
    template<typename T = std::string>
    typename std::enable_if<std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& operator,(
        T const& msg) noexcept;
    template<typename T>
    typename std::enable_if<!std::is_same<std::string,
        typename std::decay<T>::type>::value, Logger>::type& operator,(
        T const& msg) noexcept;
    template<uint32_t sz>
    Logger& operator,(char const(&msg)[sz]) noexcept;
    /// Finish log
    void finish() noexcept;
protected:
    // Some global options
    static std::string defaultLogFile;
    static Logger& hasLogger(std::string const& file) noexcept;
    /**
     * Create a logger
     * @param path if path empty only for internal emptyLogger
     * @param outputs if 0 then use default
     * @param maxSize if < 0 use kDefaultLogSize, else min kMinLogSize
     * @param trunc true to trunc file, used only when path not nil and
     * Output::File set
     */
    Logger(
        std::string const& path,
        Outputs const& outputs = Outputs{},
        int32_t const maxSize = -1,
        bool const trunc = false) noexcept;
    Logger(Logger const&) = delete;
    Logger& operator=(Logger const&) = delete;
    void tryDoAcCb(
        std::string const& name,
        LogLevel const& logLevel,
        std::string const &msg) const noexcept;
    // Logger instances and related
    static Logger emptyLogger;
    static boost::shared_mutex instancesRwlock;
    static std::map<std::string, SharedPtr<Logger> > instances;
    // Instance properties
    mutable std::mutex writemutex;
    LogLevel logLevel { LogLevel::Note };
    LogLevel spinOnceLogLevel{ LogLevel::Unchange };
    FILE* log{ nullptr };
    std::string const path;
    Outputs outputs{ Output::CoutOrCerr };
    uint32_t maxSize{ kDefaultLogSize };
    bool hasIdx{ true };
    bool hasTid{ false };
    AppendCallback appendCallback{ nullptr };
    mutable boost::shared_mutex acNameFiltersRwlock;
    /// @note empty name to filter nil and empty
    std::set<std::string> acNameFilters;
};
extern std::string LogRealTime() noexcept;
inline void Logger::setDefaultLogger(std::string const& path) noexcept
{
    if (!path.empty()) {
        Logger::defaultLogFile = path;
    }
}
inline std::string Logger::getDefaultLogger() noexcept
{
    return Logger::defaultLogFile;
}
inline Logger& Logger::getFatal(
    std::string const& path, Outputs const& outputs) noexcept
{
    return Logger::getLogger(LogLevel::Fata, path, outputs);
}
inline Logger& Logger::getError(
    std::string const& path, Outputs const& outputs) noexcept
{
    return Logger::getLogger(LogLevel::Erro, path, outputs);
}
inline Logger& Logger::getWarning(
    std::string const& path, Outputs const& outputs) noexcept
{
    return Logger::getLogger(LogLevel::Warn, path, outputs);
}
inline Logger& Logger::getNote(
    std::string const& path, Outputs const& outputs) noexcept
{
    return Logger::getLogger(LogLevel::Note, path, outputs);
}
inline Logger& Logger::getInfo(
    std::string const& path, Outputs const& outputs) noexcept
{
    return Logger::getLogger(LogLevel::Info, path, outputs);
}
inline Logger& Logger::getTrace(
    std::string const& path, Outputs const& outputs) noexcept
{
    return Logger::getLogger(LogLevel::Trac, path, outputs);
}
inline Logger& Logger::getDebug(
    std::string const& path, Outputs const& outputs) noexcept
{
    return Logger::getLogger(LogLevel::Debu, path, outputs);
}
inline Logger& Logger::getDetail(
    std::string const& path, Outputs const& outputs) noexcept
{
    return Logger::getLogger(LogLevel::Deta, path, outputs);
}
inline Logger::operator bool() const noexcept
{
    return !this->path.empty();
}
inline bool Logger::isLogable(LogLevel const& ll) const noexcept
{
    return this->logLevel >= ll;
}
inline LogLevel Logger::getLogLevel() const noexcept
{
    return this->logLevel;
}
inline void Logger::setOutputs(Outputs const& o) noexcept
{
    this->outputs = o;
}
inline void Logger::setAppendCallback(AppendCallback const& ac) noexcept
{
    this->appendCallback = ac;
}
inline void Logger::enableIdx(bool const enable) noexcept
{
    this->hasIdx = enable;
}
inline void Logger::enableTid(bool const enable) noexcept
{
    this->hasTid = enable;
}
// f
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::f(
    T const& msg) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Fata);
    return *this;
}
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::f(
    std::string const& name, T const& msg) noexcept
{
    this->append(name.c_str(), nullptr, -1, msg, LogLevel::Fata);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::f(
    T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(nullptr, nullptr, -1, ss.str(), LogLevel::Fata);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::f(
    std::string const& name, T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(name.c_str(), nullptr, -1, ss.str(), LogLevel::Fata);
    return *this;
}
template<uint32_t sz> Logger& Logger::f(char const(&msg)[sz]) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Fata);
    return *this;
}
template<uint32_t sz> Logger& Logger::f(
    std::string const& name, char const(&msg)[sz]) noexcept
{
    this->append(name, nullptr, -1, msg, LogLevel::Fata);
    return *this;
}
// e
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::e(
    T const& msg) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Erro);
    return *this;
}
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::e(
    std::string const& name, T const& msg) noexcept
{
    this->append(name.c_str(), nullptr, -1, msg, LogLevel::Erro);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::e(
    T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(nullptr, nullptr, -1, ss.str(), LogLevel::Erro);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::e(
    std::string const& name, T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(name.c_str(), nullptr, -1, ss.str(), LogLevel::Erro);
    return *this;
}
template<uint32_t sz> Logger& Logger::e(char const(&msg)[sz]) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Erro);
    return *this;
}
template<uint32_t sz> Logger& Logger::e(
    std::string const& name, char const(&msg)[sz]) noexcept
{
    this->append(name, nullptr, -1, msg, LogLevel::Erro);
    return *this;
}
// w
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::w(
    T const& msg) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Warn);
    return *this;
}
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::w(
    std::string const& name, T const& msg) noexcept
{
    this->append(name.c_str(), nullptr, -1, msg, LogLevel::Warn);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::w(
    T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(nullptr, nullptr, -1, ss.str(), LogLevel::Warn);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::w(
    std::string const& name, T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(name.c_str(), nullptr, -1, ss.str(), LogLevel::Warn);
    return *this;
}
template<uint32_t sz> Logger& Logger::w(char const(&msg)[sz]) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Warn);
    return *this;
}
template<uint32_t sz> Logger& Logger::w(
    std::string const& name, char const(&msg)[sz]) noexcept
{
    this->append(name, nullptr, -1, msg, LogLevel::Warn);
    return *this;
}
// n
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::n(
    T const& msg) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Note);
    return *this;
}
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::n(
    std::string const& name, T const& msg) noexcept
{
    this->append(name.c_str(), nullptr, -1, msg, LogLevel::Note);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::n(
    T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(nullptr, nullptr, -1, ss.str(), LogLevel::Note);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::n(
    std::string const& name, T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(name.c_str(), nullptr, -1, ss.str(), LogLevel::Note);
    return *this;
}
template<uint32_t sz> Logger& Logger::n(char const(&msg)[sz]) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Note);
    return *this;
}
template<uint32_t sz> Logger& Logger::n(
    std::string const& name, char const(&msg)[sz]) noexcept
{
    this->append(name, nullptr, -1, msg, LogLevel::Note);
    return *this;
}
// i
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::i(
    T const& msg) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Info);
    return *this;
}
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::i(
    std::string const& name, T const& msg) noexcept
{
    this->append(name.c_str(), nullptr, -1, msg, LogLevel::Info);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::i(
    T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(nullptr, nullptr, -1, ss.str(), LogLevel::Info);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::i(
    std::string const& name, T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(name.c_str(), nullptr, -1, ss.str(), LogLevel::Info);
    return *this;
}
template<uint32_t sz> Logger& Logger::i(char const(&msg)[sz]) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Info);
    return *this;
}
template<uint32_t sz> Logger& Logger::i(
    std::string const& name, char const(&msg)[sz]) noexcept
{
    this->append(name, nullptr, -1, msg, LogLevel::Info);
    return *this;
}
// d
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::d(
    T const& msg) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Debu);
    return *this;
}
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::d(
    std::string const& name, T const& msg) noexcept
{
    this->append(name.c_str(), nullptr, -1, msg, LogLevel::Debu);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::d(
    T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(nullptr, nullptr, -1, ss.str(), LogLevel::Debu);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::d(
    std::string const& name, T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(name.c_str(), nullptr, -1, ss.str(), LogLevel::Debu);
    return *this;
}
template<uint32_t sz> Logger& Logger::d(char const(&msg)[sz]) noexcept
{
    this->append(nullptr, nullptr, -1, msg, LogLevel::Debu);
    return *this;
}
template<uint32_t sz> Logger& Logger::d(
    std::string const& name, char const(&msg)[sz]) noexcept
{
    this->append(name, nullptr, -1, msg, LogLevel::Debu);
    return *this;
}
// <<
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::operator<<(
    T const& msg) noexcept
{
    this->append(nullptr, nullptr, -1, msg, this->logLevel);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::operator<<(
    T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(nullptr, nullptr, -1, ss.str(), this->logLevel);
    return *this;
}
template<uint32_t sz>
Logger& Logger::operator<<(char const(&msg)[sz]) noexcept
{
    this->append(nullptr, nullptr, -1, msg, this->logLevel);
    return *this;
}
template<typename T>
typename std::enable_if<std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::operator,(
    T const& msg) noexcept
{
    this->append(msg, this->logLevel);
    return *this;
}
template<typename T>
typename std::enable_if<!std::is_same<std::string,
    typename std::decay<T>::type>::value, Logger>::type& Logger::operator,(
    T const& msg) noexcept
{
    std::stringstream ss;
    ss << msg;
    this->append(ss.str(), this->logLevel);
    return *this;
}
template<uint32_t sz>
Logger& Logger::operator,(char const(&msg)[sz]) noexcept
{
    this->append(msg, this->logLevel);
    return *this;
}