• log4z


    1.基本介绍

    • 地址: https://github.com/zsummer/log4z
    • 支持 windows/linux/mac/android/iOS
    • 一个头文件,一个cpp
    • 日志滚动, 可以按月分文件夹
    • 线程安全
    • 彩色输出
    • 格式化或流形式的记录
    • 热更新配置
    • 多日志分流,可以输出到多个位置(logger)
    • MIT协议,基本没限制

    2. 配置项

    放到单独的配置文件中: log4z.cfg

    [Main]              # logger名字,日志分流
    path = ./log/       # 日志目录
    level = trace       # trace, debug, info, warn/warning, error, alarm, fatal
    display = false/0   # 不输出到屏幕
    outfile = false/0   # 不输出到文件
    monthdir = false/0  # 不使用月文件夹滚动
    limitsize = 10      # MB, 日志文件滚动大小
    fileline = false/0  # 是否输出源文件行,便于排查函数
    enable = false/0    # 是否启用
    reserve = 60        # s, 日志保留时间
    

    3. 接口

    3.1. ILog4zManager 是个总控,基础控制接口,下边的stream基于这个接口

    getRef();
    config(const char * configPath);    // 加载配置
    
    // 有个默认的logger: LOG4Z_MAIN_LOGGER_ID, 可以直接使用
    LoggerId createLogger(const char* key); // 创建logger分流
    LoggerId findLogger(const char* key);   // 获取
    bool enableLogger(LoggerId id, bool enable) = 0; // immediately when enable, and queue up when disable.
    bool setLoggerName(LoggerId id, const char * name) = 0;
    bool setLoggerPath(LoggerId id, const char * path) = 0;
    bool setLoggerLevel(LoggerId id, int nLevel) = 0; // immediately when enable, and queue up when disable.
    bool setLoggerFileLine(LoggerId id, bool enable) = 0;
    bool setLoggerDisplay(LoggerId id, bool enable) = 0;
    bool setLoggerOutFile(LoggerId id, bool enable) = 0;
    bool setLoggerLimitsize(LoggerId id, unsigned int limitsize) = 0;
    bool setLoggerMonthdir(LoggerId id, bool enable) = 0;
    bool setLoggerReserveTime(LoggerId id, time_t sec) = 0;
    
    
    bool start();   // 开启日志线程
    bool stop();
    

    3.2. Log4zStream 支持流式输入

    类似 stringstream
    用各种重载<<操作符,来支持各个数据类型

    比如流式输出

    LOGD("char:" << 'c'
        << ", unsigned char:" << (unsigned char) 'c'
        << ", short:" << (short)-1
        << ", unsigned short:" << (unsigned short)-1
        << ", int:" << (int)-1
        << ", unsigned int:" << (unsigned int)-1
        << ", long:" << (long)-1
        << ", unsigned long:" << (unsigned long)-1
        << ", long long:" << (long long)-1
        << ", unsigned long long:" << (unsigned long long) - 1
        << ", float:" << (float)-1.234567
        << ", double:" << (double)-2.34566
        << ", double:" << pow(2, 52) - 1.0
        << ", double:" << pow(2, 52) * -1000
        << ", double:" << pow(2, 52) / 1000
        << ", double:" << pow(2, 52) / -1000
        << ", double:" << pow(2, -58)
        << ", double:" << pow(2, -16)*-1
        << ", std::string:" << std::string("fffff")
        << ", int *:" << (int *)argv
        << ", const int *:" << (const int *)argv
        << ", constant:" << 1000
        << ", constant:" << 100.12345678
        << ", bool:" << true
        << ", show hex data:" << Log4zBinary("1234567890abcdefghigklmnopqrstuvwxyz_zyw_zsummer_log4z", 50)
    );
    

    遇到 << 1000, 会去找

    inline Log4zStream & operator <<(int t){return writeLongLong(t);}
    
    inline Log4zStream & Log4zStream::writeLongLong(long long t, int width, int dec)
    {
        if (t < 0 )
        {
            t = -t;
            writeChar('-');
        }
        writeULongLong((unsigned long long)t, width, dec);
        return *this;
    }
    
    inline Log4zStream & zsummer::log4z::Log4zStream::writeChar(char ch)
    {
        if (_end - _cur > 1)
        {
            _cur[0] = ch;   // 这里是实际写到一段内存,最后 logger 会将这段内存整体输出
            _cur++;
        }
        return *this;
    }
    

    其他格式也是这样输出的。

    3.3. 方便使用的宏

    支持流式输出的宏

    //! fast macro
    #define LOG_TRACE(id, log) LOG_STREAM(id, LOG_LEVEL_TRACE, __FILE__, __LINE__, log)
    #define LOG_DEBUG(id, log) LOG_STREAM(id, LOG_LEVEL_DEBUG, __FILE__, __LINE__, log)
    #define LOG_INFO(id, log)  LOG_STREAM(id, LOG_LEVEL_INFO, __FILE__, __LINE__, log)
    #define LOG_WARN(id, log)  LOG_STREAM(id, LOG_LEVEL_WARN, __FILE__, __LINE__, log)
    #define LOG_ERROR(id, log) LOG_STREAM(id, LOG_LEVEL_ERROR, __FILE__, __LINE__, log)
    #define LOG_ALARM(id, log) LOG_STREAM(id, LOG_LEVEL_ALARM, __FILE__, __LINE__, log)
    #define LOG_FATAL(id, log) LOG_STREAM(id, LOG_LEVEL_FATAL, __FILE__, __LINE__, log)
    
    //! super macro.
    #define LOGT( log ) LOG_TRACE(LOG4Z_MAIN_LOGGER_ID, log )
    #define LOGD( log ) LOG_DEBUG(LOG4Z_MAIN_LOGGER_ID, log )
    #define LOGI( log ) LOG_INFO(LOG4Z_MAIN_LOGGER_ID, log )
    #define LOGW( log ) LOG_WARN(LOG4Z_MAIN_LOGGER_ID, log )
    #define LOGE( log ) LOG_ERROR(LOG4Z_MAIN_LOGGER_ID, log )
    #define LOGA( log ) LOG_ALARM(LOG4Z_MAIN_LOGGER_ID, log )
    #define LOGF( log ) LOG_FATAL(LOG4Z_MAIN_LOGGER_ID, log )
    

    支持格式化的宏

    //!format string
    #define LOGFMT_TRACE(id, fmt, ...)  LOG_FORMAT(id, LOG_LEVEL_TRACE, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
    #define LOGFMT_DEBUG(id, fmt, ...)  LOG_FORMAT(id, LOG_LEVEL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
    #define LOGFMT_INFO(id, fmt, ...)  LOG_FORMAT(id, LOG_LEVEL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
    #define LOGFMT_WARN(id, fmt, ...)  LOG_FORMAT(id, LOG_LEVEL_WARN, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
    #define LOGFMT_ERROR(id, fmt, ...)  LOG_FORMAT(id, LOG_LEVEL_ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
    #define LOGFMT_ALARM(id, fmt, ...)  LOG_FORMAT(id, LOG_LEVEL_ALARM, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
    #define LOGFMT_FATAL(id, fmt, ...)  LOG_FORMAT(id, LOG_LEVEL_FATAL, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
    #define LOGFMTT( fmt, ...) LOGFMT_TRACE(LOG4Z_MAIN_LOGGER_ID, fmt,  ##__VA_ARGS__)
    #define LOGFMTD( fmt, ...) LOGFMT_DEBUG(LOG4Z_MAIN_LOGGER_ID, fmt,  ##__VA_ARGS__)
    #define LOGFMTI( fmt, ...) LOGFMT_INFO(LOG4Z_MAIN_LOGGER_ID, fmt,  ##__VA_ARGS__)
    #define LOGFMTW( fmt, ...) LOGFMT_WARN(LOG4Z_MAIN_LOGGER_ID, fmt,  ##__VA_ARGS__)
    #define LOGFMTE( fmt, ...) LOGFMT_ERROR(LOG4Z_MAIN_LOGGER_ID, fmt,  ##__VA_ARGS__)
    #define LOGFMTA( fmt, ...) LOGFMT_ALARM(LOG4Z_MAIN_LOGGER_ID, fmt,  ##__VA_ARGS__)
    #define LOGFMTF( fmt, ...) LOGFMT_FATAL(LOG4Z_MAIN_LOGGER_ID, fmt,  ##__VA_ARGS__)
    

    4. 线程模型

    一个后台线程持续往日志文件写; 各种接口线程安全。

    bool LogerManager::start()
    {
        if (_runing)    // 只会启动一个日志线程
        {
            showColorText("log4z already start 
    ", LOG_LEVEL_FATAL);
            return false;
        }
        _semaphore.create(0);
        bool ret = ThreadHelper::start();       // 启动日志线程
        return ret && _semaphore.wait(3000);    // 这里用信号量同步一下线程,等到日志线程启动后,这里再退出
    }
    

    ThreadHelper::start() 进而调用 int ret = pthread_create(&_phtreadID, NULL, threadProc, (void*)this); 启动 threadProc(),最后会调用void LogerManager::run():

    void LogerManager::run()
    {
        _runing = true;
        LOGA("-----------------  log4z thread started!   ----------------------------");
        for (int i = 0; i <= _lastId; i++)
        {
            if (_loggers[i]._enable)
            {
                LOGA("logger id=" << i
                    << " key=" << _loggers[i]._key
                    << " name=" << _loggers[i]._name
                    << " path=" << _loggers[i]._path
                    << " level=" << _loggers[i]._level
                    << " display=" << _loggers[i]._display);
            }
        }
    
        _semaphore.post(); // 通知用户线程LogerManager::start() 函数可以返回了
    
        ...
    }
    

    对线程和信号量都做了封装,以跨平台。

    // 线程封装
    class ThreadHelper
    {
    public:
        ThreadHelper(){_hThreadID = 0;}
        virtual ~ThreadHelper(){}
    public:
        bool start();
        bool wait();
        virtual void run() = 0;
    private:
        unsigned long long _hThreadID;
    #ifndef WIN32
        pthread_t _phtreadID;
    #endif
    };
    
    
    // 信号量封装
    class SemHelper
    {
    public:
        SemHelper();
        virtual ~SemHelper();
    public:
        bool create(int initcount);
        bool wait(int timeout = 0);
        bool post();
    private:
    #ifdef WIN32
        HANDLE _hSem;
    #elif defined(__APPLE__)
        dispatch_semaphore_t _semid;
    #else
        sem_t _semid;
        bool  _isCreate;
    #endif
    };
    
  • 相关阅读:
    linq to sql 扩展方法
    跨线程的安全更新控件
    WinForm程序启动控制台窗口Console
    Winfrom巧用Using设置鼠标为WaitCursor
    在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。
    基于Token的身份验证——JWT(转)
    jwt算法
    session问题总既然(深入理解)&Token问题理解&sso单点登陆理解实现
    1.spring boot要求最低jdk1.8,平安默认1.6问题,-》安装JDK1.8 2.maven 3.3.3要求最低jdk1.7->安装jdk 1.8
    批量插入删除
  • 原文地址:https://www.cnblogs.com/suntus/p/15226308.html
Copyright © 2020-2023  润新知