• 简单的后台日志组件


      日志对于软件开发者几乎是绕不开的墙,一个强大的程序需要开发者能够随时监控到每个细节,而对于记录程序的运行状态、操作记录等等更是必不可少的,当然,有很多高大上的开源日志系统可供选择,在开源中国上能搜一大堆...

      对于后台程序,我就需要一个简单、实用、稳定日志,不需要各种花里胡哨的功能,控制台输出也无妨,但最好能落地便于查找。基于此类需求,就自己开发了一个日志组件,能够融合到各类后台系统中,包含了常规的功能,能满足最低需求啦。

      功能主要包括:可同步/异步记录日志、落地/控制台(可高亮)输出、简单格式化、读取/写入一组日志到指定文件中,具体的看贴上的代码,是否对于开发者是否有帮助,请批评指正咯..

      

      ILog.h

    #ifndef _UTIL_LOG_H_
    #define _UTIL_LOG_H_
    #include <vector>
    #include <string>
    
    #define UTIL_LOG_API
    
    //日志信息默认包裹符( "[]", "()", ... )
    #define DEFAULT_TEXT_LEFT_WRAP "["
    #define DEFAULT_TEXT_RIGHT_WRAP "]"
    
    //日志信息默认分割符( "	", "-", " " )
    #define DEFAULT_TEXT_SEPARATE " "
    
    ///日志信息级别定义
    enum EU_LOG_SEVERITY
    {
        ///调试信息输出(非DEBUG模式无效)
        EU_LOG_DEBUG=0,
        
        ///正常信息输出
        EU_LOG_MSG=1,
    
        ///警告信息输出
        EU_LOG_WARN=2,
    
        ///错误信息输出
        EU_LOG_ERR=3,
    
        ///无标记信息输出
        EU_LOG_CLEAR=4
    };
    
    ///日志输出高亮颜色定义
    enum EU_TEXT_COLOR
    {
        EU_TEXT_BLACK=0,
        EU_TEXT_RED=1,
        EU_TEXT_GREEN=2,
        EU_TEXT_BROWN=3,
        EU_TEXT_BLUE=4,
        EU_TEXT_MAGENTA=5,
        EU_TEXT_CYAN=6,
        EU_TEXT_WHITE=7,
        EU_TEXT_YELLOW=8,
        EU_TEXT_LRED=9,
        EU_TEXT_LGREEN=10,
        EU_TEXT_LBLUE=11,
        EU_TEXT_LMAGENTA=12,
        EU_TEXT_LCYAN=13,
        EU_TEXT_LWHITE=14
    };
    
    ///日志回调函数定义
    ///@param severity信息级别
    ///@param msg日志信息
    ///@param len日志信息长度
    typedef void (* util_log_cb)(int severity, const char *msg, size_t len);
    
    ///类ILog
    ///@remark 日志组件接口定义
    class ILog
    {
    public:
        ///初始化日志组件
        ///@param async是否异步
        ///@param print是否输出显示
        ///@param save是否保存至文件
        ///@param defaultPath日志默认文件路径, 格式"\xxx\xxx"
        ///@param cb记录日志后回调函数指针
        ///@return 成功返回0, 失败返回负值
        virtual int init(bool async=true, bool print=true, bool save=true, 
            const char *defaultPath=".\log", util_log_cb cb=0) = 0;
    
        ///设置日志打包符号
        ///@param left_wrap左包裹符
        ///@param right_wrap右包裹符
        ///@param separate分割符
        virtual void set_text_packsign(const char *left_wrap="", const char *right_wrap="", const char *separate="	") = 0;
    
        ///设置日志输出高亮配置
        ///@param config_path配置路径
        virtual void set_text_highlight(const char *config_path) = 0;
    
        ///运行日志组件
        virtual void run() = 0;
    
        ///停止日志组件
        virtual void stop() = 0;
    
        ///记录日志, 包括屏幕显示和储存至默认路径下文件
        ///@param severity信息级别
        ///@param fmt参数传入格式
        virtual void log(EU_LOG_SEVERITY severity, const char *fmt, ...) = 0;
    
        ///记录日志, 储存至指定路径下文件, 文件格式"\xxx\xxx"
        ///@param filePath指定路径下文件
        ///@param severity信息级别
        ///@param fmt参数传入格式
        virtual void log2file(const char *filePath, EU_LOG_SEVERITY severity, const char *fmt, ...) = 0;
    
        ///读取指定路径下日志文件所有内容
        ///@param fileName文件名称
        ///@param result文件所有日志信息
        virtual void read_file_text(const char *fileName, std::vector<std::string> &result) = 0;
    
        ///写入内容到指定路径下日志文件
        ///@param fileName文件名称
        ///@param result日志内容
        virtual void write_file_text(const char *fileName, std::vector<std::string> &result) = 0;
    
    protected:
        virtual ~ILog(){}
    };
    
    ///创建日志组件
    UTIL_LOG_API ILog *CreateLoger();
    
    ///销毁日志组件
    UTIL_LOG_API void DestroyLoger(ILog *&p);
    
    #endif//_UTIL_LOG_H_

      

      Log.h

    #ifndef _UTIL_LOG_IMPL_H_
    #define _UTIL_LOG_IMPL_H_
    #include "ILog.h"
    #include <boost/thread.hpp>
    #include <boost/thread/mutex.hpp>
    #include <boost/thread/condition.hpp>
    #include <boost/make_shared.hpp>
    #include <list>
    
    ///日志信息最大长度定义, 10k
    const int log_text_max_len = 1024 * 10;
    
    ///日志信息结构定义
    struct log_message
    {
    public:
        log_message(EU_LOG_SEVERITY s,
            const std::string &p, 
            const std::string &t) : 
        m_severity(s),
            m_path(p),
            m_text(t){}
    
        EU_LOG_SEVERITY m_severity;
        std::string m_path;
        std::string m_text;
    };
    typedef boost::shared_ptr<log_message> MessagePtr;
    
    class util_log_impl : public ILog
    {
    public:
        util_log_impl();
        virtual ~util_log_impl();
    
        virtual int init(bool async, bool print, bool save, const char *defaultPath, util_log_cb cb);
    
        virtual void set_text_packsign(const char *left_wrap, const char *right_wrap, const char *separate);
    
        virtual void set_text_highlight(const char *config_path);
    
        virtual void run();
    
        virtual void stop();
    
        virtual void log(EU_LOG_SEVERITY severity, const char *fmt, ...);
    
        virtual void log2file(const char *filePath, EU_LOG_SEVERITY severity, const char *fmt, ...);
    
        virtual void read_file_text(const char *fileName, std::vector<std::string> &result);
    
        virtual void write_file_text(const char *fileName, std::vector<std::string> &result);
    
    private:
        ///设置日志输出高亮
        void set_text_highlight(std::string text, EU_TEXT_COLOR color);
    
        ///打包日志信息
        void pack_log_text(const char *filePath, EU_LOG_SEVERITY severity, const char *fmt, va_list ap);
        
        ///处理日志信息
        void handle_log_msg(const log_message &msg);
    
        ///打印日志信息
        void print_log_text(const std::string &logText);
    
        ///保存日志信息
        void save_log_text(const std::string &filePath, const std::string &logText);
    
        ///获取日志文件名称包括路径
        std::string get_log_file_name(const std::string &filePath);
    
        ///获取日志文件路径
        std::string get_log_file_path(const std::string &fileName);
    
        ///更新默认日志文件
        void update_default_file();
    
        ///异步处理日志
        void async_process_log();
    
        ///克隆日志队列当前所有信息
        void clone_log_list(std::list<MessagePtr> &messages);
    
        ///检查/创建路径
        bool check_file_path(const std::string &filePath);
        void create_file_path(const std::string &filePath);
    
    private:
        //日志状态控制
        bool m_run_state;
        bool m_async_state;
        bool m_print_state;
        bool m_save_state;
        std::string m_default_path;
        util_log_cb m_log_cb;
    
        //日志打包符号
        std::string m_left_wrap;
        std::string m_right_wrap;
        std::string m_separate;
    
        //日志输出高亮
        bool m_custom_highlight;
        std::map<std::string, EU_TEXT_COLOR> m_text_highlight_grp;
        
        //当前日志保存文件句柄
        FILE *m_current_file;
        std::string m_current_date;
    
        //日志信息队列
        boost::mutex m_mt_msg;
        boost::condition m_con_msg;
        std::list<MessagePtr> m_message_list;
        boost::shared_ptr<boost::thread> m_th_process_log;
    };
    
    #endif//_UTIL_LOG_IMPL_H_
    View Code

      Log.cpp

    #include "Log.h"
    #include "utils.h"
    #include "IniFile.h"
    #include <io.h>
    #include <direct.h>
    #include <stdarg.h>
    #include <Windows.h>
    #include <iostream>
    
    static const char *log_text_color_key[EU_TEXT_LWHITE+1] = 
    {
        "text_black",
        "text_red",
        "text_green",
        "text_brown",
        "text_blue",
        "text_magenta",
        "text_cyan",
        "text_white",
        "text_yellow",
        "text_lred",
        "text_lgreen",
        "text_lblue",
        "text_lmagenta",
        "text_lcyan",
        "text_lwhite"
    };
    
    static const WORD log_text_color_value[EU_TEXT_LWHITE+1] =
    {
        0, //BLACK
        FOREGROUND_RED, //RED
        FOREGROUND_GREEN, //GREEN
        FOREGROUND_RED | FOREGROUND_GREEN, //BROWN
        FOREGROUND_BLUE, //BLUE
        FOREGROUND_RED | FOREGROUND_BLUE, //MAGENTA
        FOREGROUND_GREEN | FOREGROUND_BLUE, //CYAN
        FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, //WHITE
        FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, //YELLOW
        FOREGROUND_RED | FOREGROUND_INTENSITY, //RED_BOLD
        FOREGROUND_GREEN | FOREGROUND_INTENSITY, //GREEN_BOLD
        FOREGROUND_BLUE | FOREGROUND_INTENSITY, //BLUE_BOLD
        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY, //MAGENTA_BOLD
        FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, //CYAN_BOLD
        FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY //WHITE_BOLD
    };
    
    ILog *CreateLoger()
    {
        return new util_log_impl();
    }
    void DestroyLoger(ILog *&p)
    {
        if (p)
        {
            delete (util_log_impl *)p;
            p = 0;
        }
    }
    
    util_log_impl::util_log_impl()
    {
        m_run_state = false;
        m_async_state = false;
        m_print_state = false;
        m_save_state  = false;
        m_log_cb = 0;
        m_current_file = 0;
    
        m_custom_highlight = false;
    }
    
    util_log_impl::~util_log_impl()
    {
        stop();
    }
    
    int util_log_impl::init(bool async, bool print, bool save, const char *defaultPath, util_log_cb cb)
    {
        m_run_state = false;
        m_async_state = async;
        m_print_state = print;
        m_save_state  = save;
    
        if (m_save_state && defaultPath)
        {
            m_default_path = defaultPath;
    
            if (!check_file_path(m_default_path))
            {
                create_file_path(m_default_path);
            }
        }
    
        m_log_cb = cb;
        m_current_file = 0;
    
        char temp[32] = {0};
        NS_UTILS::get_current_date(temp, sizeof(temp));
        m_current_date = temp;
    
        m_left_wrap = DEFAULT_TEXT_LEFT_WRAP;
        m_right_wrap = DEFAULT_TEXT_RIGHT_WRAP;
        m_separate = DEFAULT_TEXT_SEPARATE;
    
        return 0;
    }
    
    void util_log_impl::set_text_packsign(const char *left_wrap, const char *right_wrap, const char *separate)
    {
        if (m_run_state)
        {
            //已启动不处理
            return;
        }
    
        m_left_wrap = left_wrap;
        m_right_wrap = right_wrap;
        m_separate = separate;
    }
    
    void util_log_impl::set_text_highlight(const char *config_path)
    {
        if (m_run_state)
        {
            return;
        }
    
        if (config_path)
        {
            IniFile config(config_path);
            config.setSection("LOGHIGHLIGHTCONFIG");
    
            std::string color_value;
            for (int i=EU_TEXT_BLACK; i<EU_TEXT_LWHITE; ++i)
            {
                color_value = config.readStr(log_text_color_key[i], "");
                if (!color_value.empty())
                {
                    set_text_highlight(color_value, (EU_TEXT_COLOR)i);
                }
            }
    
            if (!m_text_highlight_grp.empty())
            {
                m_custom_highlight = true;
            }
        }
    }
    
    void util_log_impl::set_text_highlight(std::string text, EU_TEXT_COLOR color)
    {
        text = text + std::string("|");
    
        char *temp = (char *)text.c_str();
        char *p = strtok(temp, "|");
        while (p)
        {
            if (strlen(p)>0)
            {
                m_text_highlight_grp.insert(std::make_pair(std::string(p), color));
            }
    
            p = strtok(NULL, "|");
        }
    }
    
    void util_log_impl::run()
    {
        if (m_run_state)
        {
            return;
        }
        m_run_state = true;
    
        if (m_async_state && !m_th_process_log)
        {
            m_th_process_log = boost::make_shared<boost::thread>(boost::bind(&util_log_impl::async_process_log, this));
        }
    }
    
    void util_log_impl::stop()
    {
        if (!m_run_state)
        {
            //已停止不处理
            return;
        }
        m_run_state = false;
    
        if (m_async_state && m_th_process_log)
        {
            //通知线程退出
            {
                boost::mutex::scoped_lock lock(m_mt_msg);
                m_con_msg.notify_all();
            }
            m_th_process_log->join();
            m_th_process_log.reset();
        }
    
        if (m_current_file)
        {
            //关闭句柄
            fclose(m_current_file);
            m_current_file = 0;
        }
    }
    
    void util_log_impl::log(EU_LOG_SEVERITY severity, const char *fmt, ...)
    {
        assert(fmt);
    
        if (!m_run_state)
        {
            return;
        }
    
        va_list ap;
        va_start(ap, fmt);
        pack_log_text(0, severity, fmt, ap);
        va_end(ap);
    }
    
    void util_log_impl::log2file(const char *filePath, EU_LOG_SEVERITY severity, const char *fmt, ...)
    {
        assert(filePath && fmt);
    
        if (!m_run_state)
        {
            return;
        }
    
        va_list ap;
        va_start(ap, fmt);
        pack_log_text(filePath, severity, fmt, ap);
        va_end(ap);
    }
    
    void util_log_impl::read_file_text(const char *fileName, std::vector<std::string> &result)
    {
        if (fileName)
        {
            FILE *file = _fsopen(fileName, "r", _SH_DENYWR);
            if (file)
            {
                char temp[log_text_max_len] = {0};
                while (fgets(temp, log_text_max_len, file))
                {
                    result.push_back(temp);
                    temp[0] = '';
                }
    
                fclose(file);
            }
        }
    }
    
    void util_log_impl::write_file_text(const char *fileName, std::vector<std::string> &result)
    {
        if (fileName)
        {
            std::string file_path = get_log_file_path(fileName);
            if (!file_path.empty() && !check_file_path(file_path))
            {
                create_file_path(file_path);
            }
    
            FILE *file = _fsopen(fileName, "w+", _SH_DENYWR);
            if (file)
            {
                std::string temp;
                for (size_t i=0; i<result.size(); ++i)
                {
                    temp = result[i] + std::string("
    ");
                    fwrite(temp.c_str(), 1, temp.length(), file);
                }
    
                fflush(file);
                fclose(file);
            }
        }
    }
    
    void util_log_impl::pack_log_text(const char *filePath, EU_LOG_SEVERITY severity, const char *fmt, va_list ap)
    {
        assert(fmt);
    
        char buffer[log_text_max_len] = {0};
        my_vsprintf(buffer, sizeof(buffer)-1, fmt, ap);
    
        char temp[32] = {0};
        NS_UTILS::get_current_time(temp, sizeof(temp));
        std::string now_time = temp;
    
        //设置信息级别
        const char *severity_str = 0;
        switch(severity)
        {
        case EU_LOG_DEBUG:
            {
    #ifndef _DEBUG
                return;
    #endif
                severity_str = "调试";
            }
            break;
        case EU_LOG_MSG:
            {
                severity_str = "正常";
            }
            break;
        case EU_LOG_WARN:
            {
                severity_str = "警告";
            }
            break;
        case EU_LOG_ERR:
            {
                severity_str = "错误";
            }
            break;
        case EU_LOG_CLEAR:
        default:
            {
                severity_str = "";
            }
        }
    
        std::string text;
        if (strlen(severity_str) > 0)
        {
            text = m_left_wrap + now_time + m_right_wrap + m_separate
                + m_left_wrap + severity_str + m_right_wrap + m_separate
                + buffer + "
    ";
        }
        else
        {
            text = m_left_wrap + now_time + m_right_wrap + m_separate
                + buffer + "
    ";
        }
    
        std::string path("");
        if (filePath)
        {
            //指定特殊存储路径
            path = filePath;
        }
    
        MessagePtr packet = boost::make_shared<log_message>(severity, path, text);
        if (m_async_state)
        {
            //数据进队列, 通知线程处理
            boost::mutex::scoped_lock lock(m_mt_msg);
            m_message_list.push_back(packet);
            m_con_msg.notify_one();
        }
        else
        {
            handle_log_msg(*packet.get());
        }
    }
    
    void util_log_impl::handle_log_msg(const log_message &msg)
    {
        if (m_save_state || !msg.m_path.empty())
        {
            save_log_text(msg.m_path, msg.m_text);
        }
    
        if (m_print_state)
        {
            print_log_text(msg.m_text);
        }
    
        if (m_log_cb)
        {
            //回调通知
            m_log_cb(msg.m_severity, msg.m_text.c_str(), msg.m_text.length());
        }
    }
    
    void util_log_impl::print_log_text(const std::string &logText)
    {
        if (m_custom_highlight)
        {
            int color_index = -1;
    
            //查找相应的颜色
            std::map<std::string, EU_TEXT_COLOR>::iterator iter = m_text_highlight_grp.begin();
            for (; iter!=m_text_highlight_grp.end(); ++iter)
            {
                if (logText.find(iter->first) != std::string::npos)
                {
                    color_index = iter->second;
                    break;
                }
            }
    
            if (color_index != -1)
            {
                //设置输出颜色
                HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
                SetConsoleTextAttribute(hConsole, log_text_color_value[color_index]);
    
                printf(logText.c_str());
    
                //重置输出颜色
                SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED);
                return;
            }
        }
    
        printf(logText.c_str());
    }
    
    void util_log_impl::save_log_text(const std::string &filePath, const std::string &logText)
    {
        if (!filePath.empty())
        {
            if (!check_file_path(filePath))
            {
                create_file_path(filePath);
            }
    
            std::string fileName = get_log_file_name(filePath);
            FILE *file = _fsopen(fileName.c_str(), "a", _SH_DENYWR);
            if (file)
            {
                fwrite(logText.c_str(), 1, logText.length(), file);
                fflush(file);
                fclose(file);
            }
        }
        else
        {
            //更新日志文件
            update_default_file();
    
            if (m_current_file)
            {
                fwrite(logText.c_str(), 1, logText.length(), m_current_file);
                fflush(m_current_file);
            }
        }
    }
    
    std::string util_log_impl::get_log_file_name(const std::string &filePath)
    {
        char temp[32] = {0};
        NS_UTILS::get_current_date(temp, sizeof(temp));
        std::string now_date = temp;
    
        return (filePath + "\"+ now_date + ".log");
    }
    
    std::string util_log_impl::get_log_file_path(const std::string &fileName)
    {
        size_t pos = fileName.find_last_of("\");
        if (pos != std::string::npos)
        {
            return fileName.substr(0, pos);
        }
        else
        {
            return std::string("");
        }
    }
    
    void util_log_impl::update_default_file()
    {
        char temp[32] = {0};
        NS_UTILS::get_current_date(temp, sizeof(temp));
        std::string now_date = temp;
    
        if (!m_current_file || now_date!=m_current_date)
        {
            if (m_current_file)
            {
                fclose(m_current_file);
                m_current_file = 0;
            }
    
            //更新文件日期
            m_current_date = now_date;
    
            std::string fileName = m_default_path+ "\"+ m_current_date + ".log";
            m_current_file = _fsopen(fileName.c_str(), "a", _SH_DENYWR);
        }
    }
    
    void util_log_impl::async_process_log()
    {
        while (m_run_state)
        {
            std::list<MessagePtr> messages;
            clone_log_list(messages);
    
            while (!messages.empty())
            {
                handle_log_msg(*messages.front());
                messages.pop_front();
            }
        }
    }
    
    void util_log_impl::clone_log_list(std::list<MessagePtr> &messages)
    {
        boost::mutex::scoped_lock lock(m_mt_msg);
        if (m_message_list.empty())
        {
            //等待日志信息写入
            m_con_msg.wait(m_mt_msg);
        }
        
        messages = m_message_list;
        m_message_list.clear();
    }
    
    bool util_log_impl::check_file_path(const std::string &filePath)
    {
        return (::access(filePath.c_str(), 0)==0);
    }
    
    void util_log_impl::create_file_path(const std::string &filePath)
    {
        char *tmp = (char *)filePath.c_str();
        int len = strlen(tmp);
        for(int i=0; i<len; ++i)
        {
            if(tmp[i]=='\')
            {
                tmp[i]='';
                _mkdir(tmp);
                tmp[i]='\';
            }
        }
    
        if(len>0)
        {
            _mkdir(tmp);
        }
    }
    View Code

      

  • 相关阅读:
    栅栏与自由
    如何种玉米和黄豆
    除了CRUD也要注意IO
    奶糖测试
    看你知道不知道VB6的模块之间循环关系
    [zz]C++类模板
    [zz]C++中std::tr1::function和bind 组件的使用
    [zz]c/c++一些库
    [zz] Python性能鸡汤
    [zz]Linux 下 socket 编程示例
  • 原文地址:https://www.cnblogs.com/walker-lc/p/3498948.html
Copyright © 2020-2023  润新知