我是靠谱客的博主 鲜艳绿草,最近开发中收集的这篇文章主要介绍仿muduo日志库:c++小巧日志库实现仿muduo日志库:c++小巧日志库实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

仿muduo日志库:c++小巧日志库实现

  • logger.h
#pragma once
#include <iostream>
#include <chrono>
#include <string.h> 
#include "log_stream.h" 

class Logger
{
public:
    /**
     * @brief 日志等级
     */
    enum LogLevel
    {
        TRACE,
        DEBUG,
        INFO,
        WARN,
        ERROR,
        FATAL,
        NUM_LOG_LEVELS,
    };

    //compile time calculation of basename of source file 
    /**
     * @brief 获取日志打印所在文件
     */
    class SourceFile
    {
    public:
        template<int N>
        inline SourceFile(const char(&arr)[N])
            :m_data(arr),
            m_size(N - 1) 
        {
            const char* slash = strrchr(m_data, '/'); // builtin function 
            if (slash) 
            {
                m_data = slash + 1;
                m_size -= static_cast<int>(m_data - arr);
            }
        }

        explicit SourceFile(const char* filename)
            : m_data(filename) 
        {
            const char* slash = strrchr(filename, '/');
            if (slash) 
            {
                m_data = slash + 1;
            }
            m_size = static_cast<int>(strlen(m_data));
        }

        const char* m_data;  // 当前字符串
        int m_size;          // 当前字符串大小
    };

    /**
     * @brief Logger构造
     * @param p_file:所在文件
     * @param p_nline:所在行
     */
    Logger(SourceFile p_file, int p_nline);

    /**
     * @brief Logger构造
     * @param p_file:所在文件
     * @param p_nline:所在行
     * @param p_enumLevel:日志等级
     */
    Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel);

    /**
    * @brief Logger构造
    * @param p_file:所在文件
    * @param p_nline:所在行
    * @param p_enumLevel:日志等级
    * @param p_func: 附带字符串
    */
    Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel, const char* p_func);

    /**
     * @brief Logger构造
     * @param p_file:所在文件
     * @param p_nline:所在行
     * @param p_btoAbort: 布尔判断:传true:FATAL  false:ERROR
     */
    Logger(SourceFile p_file, int p_nline, bool p_btoAbort);
    ~Logger();

    /**
     * @brief 设置日志等级
     * @param p_enumLevel:日志等级
     */
    static void setLogLevel(LogLevel p_enumLevel);

    /**
     * @brief 获取日志等级
     */
    static LogLevel logLevel();

    /**
     * @brief 获取输出字符串流
     */
    LogStream& stream() { return m_impl.m_stream; }

    typedef void (*outputFunc)(const char* msg, int len);
    typedef void (*flushFunc)();

    /**
     * @brief 设置Output回调
     */
    static void setOutput(outputFunc);
    /**
     * @brief 设置flushFunc回调
     */
    static void setFlush(flushFunc);

private:
    Logger(const Logger& lg);           //no copyable 
    Logger& operator=(const Logger& lg);

    class Impl
    {
    public:
        typedef Logger::LogLevel LogLevel;

        /**
         * @brief Impl构造
         * @param p_enumLevel:日志等级
         * @param p_nOldErrno: 错误码
         * @param p_file:所在文件
         * @param p_nline:所在行
         */
        Impl(LogLevel p_enumLevel, int p_nOldErrno, const SourceFile& p_file, int p_nline);

        /**
         * @brief 获取当前时间,精确到纳秒
         */
        void formatTime();

        /**
         * @brief 结束符-换行
         */
        void finish();

        std::chrono::system_clock::time_point m_time;     // 时间参数
        LogStream m_stream;                               // 字符串流
        LogLevel m_level;                                 // 日志等级
        int m_line;                                       // 行号
        SourceFile m_fileBaseName;                        // 文件名
    };

    Impl m_impl;       // 

};


#define log_trace if (Logger::logLevel() <= Logger::TRACE) Logger(__FILE__, __LINE__, Logger::TRACE, __func__).stream()
#define log_info if (Logger::logLevel() <= Logger::INFO) Logger(__FILE__, __LINE__).stream()
#define log_warn Logger(__FILE__, __LINE__, Logger::WARN).stream() 
#define log_debug Logger(__FILE__, __LINE__, Logger::DEBUG).stream()
#define log_error Logger(__FILE__, __LINE__, Logger::ERROR).stream() 
#define log_fatal Logger(__FILE__, __LINE__, Logger::FATAL).stream() 
#define log_syserr Logger(__FILE__, __LINE__, false).stream() 
#define log_sysfatal Logger(__FILE__, __LINE__, true).stream() 

  • logger.cpp
//Logger 
#define _CRT_SECURE_NO_WARNINGS
#include <time.h> 
#include <stdint.h> 
#include <stdlib.h> 
#include <assert.h> 
#include <stdio.h> 
#include <errno.h> 
#include <string.h> 
#include "logger.h" 
#include <ctime>
#include <sstream>

Logger::LogLevel g_logLevel = Logger::INFO;

void Logger::setLogLevel(LogLevel p_enumLevel)
{
    g_logLevel = p_enumLevel;
}

Logger::LogLevel Logger::logLevel() 
{
    return g_logLevel;
}

const char* LogLevelName[Logger::NUM_LOG_LEVELS] =
{
    "[TRACE]",
    "[DEBUG]",
    "[INFO ]",
    "[WARN ]",
    "[ERROR]",
    "[FATAL]",
};

// helper class for known string length at compile time 
class T
{
public:
    T(const char* str, unsigned len)
        :m_str(str),
        m_len(len)
    {
        assert(strlen(str) == m_len);
    }

    const char* m_str;
    const unsigned m_len;
};

void defaultOutput(const char* msg, int len) 
{
    size_t n = fwrite(msg, 1, len, stdout);
    (void)n;
}

void defaultFlush() {
    fflush(stdout);
}

Logger::outputFunc g_output = defaultOutput;
Logger::flushFunc g_flush = defaultFlush;

void Logger::setOutput(outputFunc out) 
{
    g_output = out;
}

void Logger::setFlush(flushFunc flush) 
{
    g_flush = flush;
}

Logger::Logger(SourceFile p_file, int p_nline)
    : m_impl(INFO, 0, p_file, p_nline)
{
}

Logger::Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel)
    : m_impl(p_enumLevel, 0, p_file, p_nline)
{
}

Logger::Logger(SourceFile p_file, int p_nline, bool p_btoAbort)
    : m_impl(p_btoAbort ? FATAL : ERROR, errno, p_file, p_nline)
{
}

Logger::Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel, const char* p_func)
    : m_impl(p_enumLevel, 0, p_file, p_nline)
{
    m_impl.m_stream << '[' << p_func << "] ";
}

Logger::~Logger() 
{
    m_impl.finish();
    const LogStream::Buffer& buf(stream().buffer());
    g_output(buf.data(), buf.length());
    // FATAL 致命bug日志,程序崩溃
    if (m_impl.m_level == FATAL)
    {
        g_flush();
        //abort();
    }
}

Logger::Impl::Impl(LogLevel p_enumLevel, int p_nOldErrno, const SourceFile& p_file, int p_nline)
    : m_time(std::chrono::system_clock::now()),
    m_stream(),
    m_level(p_enumLevel),
    m_fileBaseName(p_file),
    m_line(p_nline)
{
    formatTime();
    m_stream << LogLevelName[p_enumLevel] << ' ';
    m_stream << '[' << m_fileBaseName.m_data << ':' << m_line << "] ";

    std::ostringstream oss;
    oss << std::this_thread::get_id();
    m_stream << '[' << oss.str().c_str() << "] ";
    if (p_nOldErrno != 0)
    {
        m_stream /*<< strerror_tl(savedErrno)*/ << " (errno=" << p_nOldErrno << ") ";
    }
}

void Logger::Impl::finish()
{
    m_stream << 'n';
}

void Logger::Impl::formatTime()
{
    auto tt = std::chrono::system_clock::to_time_t(m_time);
    struct tm* ptm = localtime(&tt);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(m_time.time_since_epoch()) % 1000;
    auto cs = std::chrono::duration_cast<std::chrono::microseconds>(m_time.time_since_epoch()) % 1000000;
    auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(m_time.time_since_epoch()) % 1000000000;

    char date[128] = { 0 };
    sprintf(date, "[%d-%02d-%02d %02d:%02d:%02d:%03ld:%03ld:%03ld] ",
        (int)ptm->tm_year + 1900, (int)ptm->tm_mon + 1, (int)ptm->tm_mday,
        (int)ptm->tm_hour, (int)ptm->tm_min, (int)ptm->tm_sec, ms.count(), cs.count() % 1000, ns.count() % 1000);


    m_stream << date;
}
  • log_stream.h
#pragma once
#include <stdio.h> 
#include <string.h> 
#include <thread>

const int kSmallBuffer = 4096;
const int kLargeBuffer = 4096;

template<int SIZE>
class LogBuffer
{
public:
    LogBuffer() : m_cur(m_data) {}
    ~LogBuffer() {}

    /**
     * @brief 拼接字符串
     * @param p_chBuf: 字符串
     * @param p_nlen: 字符串长度
     */
    void append(const char* p_chBuf, size_t p_nlen)
    {
        // append partially 
        if ((avail()) > p_nlen)
        {
            memcpy(m_cur, p_chBuf, p_nlen);
            m_cur += p_nlen;
        }
    }

    // write in m_data directly 
    /**
     * @brief 获取当前字符串
     */
    char* current() { return m_cur; };

    /**
     * @brief 判断当前追加字符串是否超过最大限制
     */
    int avail() const { return static_cast<int> (end() - m_cur); }

    /**
     * @brief 字符串偏移
     * @param p_nlen: 偏移量
     */
    void add(size_t p_nlen) { m_cur += p_nlen; }

    /**
     * @brief 获取长度
     */
    int length() const { return m_cur - m_data; }

    /**
     * @brief 获取字符串
     */
    const char* data() const { return m_data; }

private:
    /**
     * @brief 获取字符串最后位置节点
     */
    const char* end() const { return m_data + sizeof(m_data); }

    char m_data[SIZE];      // 输出日志的char数组
    char* m_cur;            // 传入字符串
};

class LogStream 
{
public:
    LogStream();
    ~LogStream();

    using Buffer = LogBuffer<kSmallBuffer>;
    using self = LogStream;
    /**
     * @ 一系列重载
     */
    self& operator<<(bool v);
    self& operator<<(short);
    self& operator<<(unsigned short);
    self& operator<<(int);
    self& operator<<(unsigned int);
    self& operator<<(long);
    self& operator<<(unsigned long);
    self& operator<<(long long);
    self& operator<<(unsigned long long);
    self& operator<<(const void*);
    self& operator<<(float v);
    self& operator<<(double);
    self& operator<<(char v);
    self& operator<<(const char*);

    /**
     * @brief 往流缓存追加字符串
     * @param p_chData:字符串
     * @param p_nlen:字符串长度
     */
    void append(const char* p_chData, int p_nlen) { return m_buffer.append(p_chData, p_nlen); }

    /**
     * @brief 获取流缓存
     */
    const Buffer& buffer() const { return m_buffer; }

private:
    LogStream(const LogStream& ls);         //no copyable 
    LogStream& operator=(const LogStream& ls);

    template<typename T>
    void formatInteger(T v);

    Buffer m_buffer;                         // 流缓存
    static const int kMaxNumericSize = 32;

};

class Fmt 
{
public:
    template<typename T>
    Fmt(const char* fmt, T val);

    const char* data() const { return m_buf; }
    int length() const { return m_length; }

private:
    char m_buf[32];     // 字符串
    int m_length;       // 字符串长度
};

/**
 * @brief 追加流(实现与cout一样输出格式的关键)
 * @param p_stLog: 流
 * @param p_fmt:格式化类
 */
inline LogStream& operator<<(LogStream& p_stLog, const Fmt& p_fmt) 
{
    p_stLog.append(p_fmt.data(), p_fmt.length());
    return p_stLog;
}

  • log_stream.cpp
//LogStream 
#include <stdio.h> 
#include <assert.h> 
#include <algorithm> 
#include "log_stream.h" 

LogStream::LogStream() {}

LogStream::~LogStream() {}

LogStream& LogStream::operator<<(bool v)
{
    m_buffer.append(v ? "1" : "0", 1);
    return *this;
}


LogStream& LogStream::operator<<(short v) 
{
    *this << static_cast<int>(v);
    return *this;
}

LogStream& LogStream::operator<<(unsigned short v)
{
    *this << static_cast<unsigned int>(v);
    return *this;
}

LogStream& LogStream::operator<<(int v)
{
    formatInteger(v);
    return *this;
}

LogStream& LogStream::operator<<(unsigned int v)
{
    formatInteger(v);
    return *this;
}

LogStream& LogStream::operator<<(long v)
{
    formatInteger(v);
    return *this;
}

LogStream& LogStream::operator<<(unsigned long v)
{
    formatInteger(v);
    return *this;
}

LogStream& LogStream::operator<<(long long v)
{
    formatInteger(v);
    return *this;
}

LogStream& LogStream::operator<<(unsigned long long v)
{
    formatInteger(v);
    return *this;
}


LogStream& LogStream::operator<<(const void*) 
{
    printf("undefinen");
    return *this;
}

LogStream& LogStream::operator<<(float v)
{
    *this << static_cast<double>(v);
    return *this;
}

LogStream& LogStream::operator<<(double v) 
{
    if (m_buffer.avail() >= kMaxNumericSize) 
    {
        int len = snprintf(m_buffer.current(), kMaxNumericSize, "%.12g", v);
        m_buffer.add(len);
    }
    return *this;
}

LogStream& LogStream::operator<<(char v)
{
    m_buffer.append(&v, 1);
    return *this;
}

LogStream& LogStream::operator<<(const char* str)
{
    if (str) 
    {
        m_buffer.append(str, strlen(str));
    }
    else 
    {
        m_buffer.append("(NULL)", 6);
    }

    return *this;
}

const char digits[] = "9876543210123456789";
const char* zero = digits + 9;

//convert to str 
template<typename T>
size_t convert(char buf[], T value)
{
    T i = value;
    char* p = buf;

    do 
    {
        int lsd = static_cast<int>(i % 10);
        i /= 10;
        *p++ = zero[lsd];
    } while (i != 0);

    if (value < 0) 
    {
        *p++ = '-';
    }

    *p = '';
    std::reverse(buf, p);

    return p - buf;
}

template<typename T>
void LogStream::formatInteger(T v)
{
    if (m_buffer.avail() >= kMaxNumericSize) 
    {
        size_t len = convert(m_buffer.current(), v);
        m_buffer.add(len);
    }
}

template<typename T>
Fmt::Fmt(const char* fmt, T val)
{
    m_length = snprintf(m_buf, sizeof(m_buf), fmt, val);
    assert(static_cast<size_t>(m_length) < sizeof(m_buf));
}

// Explicit instantiations 

template Fmt::Fmt(const char* fmt, char);

template Fmt::Fmt(const char* fmt, short);
template Fmt::Fmt(const char* fmt, unsigned short);
template Fmt::Fmt(const char* fmt, int);
template Fmt::Fmt(const char* fmt, unsigned int);
template Fmt::Fmt(const char* fmt, long);
template Fmt::Fmt(const char* fmt, unsigned long);
template Fmt::Fmt(const char* fmt, long long);
template Fmt::Fmt(const char* fmt, unsigned long long);

template Fmt::Fmt(const char* fmt, float);
template Fmt::Fmt(const char* fmt, double);

  • main.cpp
#include "logger.h"

int main()
{
    // 计时
    auto begintime = std::chrono::system_clock::now();

    auto func_Print = []() ->void
    {
        for (int i = 0; i < 3; ++i)
        {
            log_info << "1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs.";
            log_debug << "2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test.";
            log_error << "3、这只是其中一部分。это только часть .これはほんの一部です。This is just part of it.Das ist nur ein Teil davon.";
            log_fatal << "4、Это тест.これはテストです,this is a test, Das ist ein Test.";
        }
    };

    std::thread j1print(func_Print);
    std::thread j2print(func_Print);
    std::thread j3print(func_Print);
    
    if (j1print.joinable())
        j1print.join();
    if (j2print.joinable())
        j2print.join();
    if (j3print.joinable())
        j3print.join();

    auto endtime = std::chrono::system_clock::now();
    auto TimeCount = std::chrono::duration<double, std::milli>(endtime - begintime).count();

    log_info << "**************************************程序运行所用时间:" << TimeCount << "ms.**************************************";

    return 0;
}
  • 打印输出
[2022-11-17 20:20:17:582:739:100] [FATAL] [F:VsProjectsloglog.cpp:15] [5504] 4、Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:582:456:500] [DEBUG] [F:VsProjectsloglog.cpp:13] [9680] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:582:802:900] [INFO ] [F:VsProjectsloglog.cpp:12] [20120] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs.
[2022-11-17 20:20:17:582:879:000] [ERROR] [F:VsProjectsloglog.cpp:14] [9680] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon.
[2022-11-17 20:20:17:582:879:700] [INFO ] [F:VsProjectsloglog.cpp:12] [5504] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs.
[2022-11-17 20:20:17:582:982:400] [FATAL] [F:VsProjectsloglog.cpp:15] [9680] 4、Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:582:939:100] [DEBUG] [F:VsProjectsloglog.cpp:13] [20120] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:583:067:400] [DEBUG] [F:VsProjectsloglog.cpp:13] [5504] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:583:239:100] [ERROR] [F:VsProjectsloglog.cpp:14] [20120] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon.
[2022-11-17 20:20:17:583:112:100] [INFO ] [F:VsProjectsloglog.cpp:12] [9680] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs.
[2022-11-17 20:20:17:583:316:600] [ERROR] [F:VsProjectsloglog.cpp:14] [5504] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon.
[2022-11-17 20:20:17:584:568:000] [FATAL] [F:VsProjectsloglog.cpp:15] [5504] 4、Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:584:265:200] [DEBUG] [F:VsProjectsloglog.cpp:13] [9680] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:583:647:400] [FATAL] [F:VsProjectsloglog.cpp:15] [20120] 4、Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:585:002:800] [INFO ] [F:VsProjectsloglog.cpp:12] [5504] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs.
[2022-11-17 20:20:17:589:688:300] [DEBUG] [F:VsProjectsloglog.cpp:13] [5504] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:589:930:600] [ERROR] [F:VsProjectsloglog.cpp:14] [5504] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon.
[2022-11-17 20:20:17:589:356:900] [INFO ] [F:VsProjectsloglog.cpp:12] [20120] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs.
[2022-11-17 20:20:17:588:917:900] [ERROR] [F:VsProjectsloglog.cpp:14] [9680] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon.
[2022-11-17 20:20:17:590:575:100] [FATAL] [F:VsProjectsloglog.cpp:15] [9680] 4、Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:590:112:200] [FATAL] [F:VsProjectsloglog.cpp:15] [5504] 4、Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:590:371:700] [DEBUG] [F:VsProjectsloglog.cpp:13] [20120] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:594:118:200] [INFO ] [F:VsProjectsloglog.cpp:12] [9680] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs.
[2022-11-17 20:20:17:594:105:500] [ERROR] [F:VsProjectsloglog.cpp:14] [20120] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon.
[2022-11-17 20:20:17:594:282:000] [DEBUG] [F:VsProjectsloglog.cpp:13] [9680] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:594:575:900] [FATAL] [F:VsProjectsloglog.cpp:15] [20120] 4、Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:594:619:600] [ERROR] [F:VsProjectsloglog.cpp:14] [9680] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon.
[2022-11-17 20:20:17:596:351:200] [FATAL] [F:VsProjectsloglog.cpp:15] [9680] 4、Это тест.これはテストです,this is a test, Das ist ein Test.
[2022-11-17 20:20:17:596:792:800] [INFO ] [F:VsProjectsloglog.cpp:33] [20084] **************************************程序运行所用时间:25.8867ms.**************************************

参考链接: 一个轻巧高效的多线程c++stream风格异步日志(一)

最后

以上就是鲜艳绿草为你收集整理的仿muduo日志库:c++小巧日志库实现仿muduo日志库:c++小巧日志库实现的全部内容,希望文章能够帮你解决仿muduo日志库:c++小巧日志库实现仿muduo日志库:c++小巧日志库实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部