zoukankan      html  css  js  c++  java
  • 日志系统实现

    一、使用原因:

        在实现高并发的服务器日志系统过程中,由于在工作线程中直接进行IO操作,相比较于高速的CPU,IO磁盘操作是很慢的,直接在某些工作线程(包括UI线程)写文件,程序执行速度太慢,尤其是当日志数据比较多的时候,此时,我们可以使用一个队列,需要写日志时,将日志加入队列中,另外一个专门的日志线程来写日志。

    二、代码如下:

    Logger.h:

    #ifndef __LOGGER_H__  
    #define __LOGGER_H__  
    
    #include <string>  
    #include <memory>  
    #include <thread>  
    #include <mutex>  
    #include <condition_variable>  
    #include <list>  
    
    //struct FILE;  
    
    #define LogInfo(...)        Logger::GetInstance().AddToQueue("INFO", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)  
    #define LogWarning(...)     Logger::GetInstance().AddToQueue("WARNING", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)  
    #define LogError(...)       Logger::GetInstance().AddToQueue("ERROR", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)  
    
    class Logger
    {
    public:
        static Logger& GetInstance();
    
        void SetFileName(const char* filename);
        bool Start();
        void Stop();
    
        void AddToQueue(const char* pszLevel, const char* pszFile, int lineNo, const char* pszFuncSig, char* pszFmt, ...);
    
    private:
        Logger() = default;
        Logger(const Logger& rhs) = delete;
        Logger& operator =(Logger& rhs) = delete;
    
        void threadfunc();
    
    
    private:
        std::string                     filename_;
        FILE*                           fp_{};
        std::shared_ptr<std::thread>    spthread_;
        std::mutex                      mutex_;
        std::condition_variable         cv_;            //有新的日志到来的标识  
        bool                            exit_{ false };
        std::list<std::string>          queue_;
    };
    
    #endif //!__LOGGER_H__ 
    View Code

    Logger.cpp:

    #include "stdafx.h"
    #include <windows.h>
    #include "Logger.h"  
    #include <time.h>  
    #include <stdio.h>  
    #include <memory>  
    #include <stdarg.h>  
    
    Logger& Logger::GetInstance() 
    {
        static Logger logger;
        return logger;
    }
    
    void Logger::SetFileName(const char* filename)
    {
        filename_ = filename;
    }
    
    bool Logger::Start()
    {
        if (filename_.empty())
        {
            time_t now = time(NULL);
            struct tm* t = localtime(&now);
            char timestr[64] = { 0 };
            sprintf(timestr, "%04d%02d%02d%02d%02d%02d.imserver.log", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
            filename_ = timestr;
        }
    
        fp_ = fopen(filename_.c_str(), "wt+");
        if (fp_ == NULL)
            return false;
    
        spthread_.reset(new std::thread(std::bind(&Logger::threadfunc, this)));
    
        return true;
    }
    
    void Logger::Stop()
    {
        exit_ = true;
        cv_.notify_one();
    
        //等待时间线程结束  
        spthread_->join();
    }
    
    void Logger::AddToQueue(const char* pszLevel, const char* pszFile, int lineNo, const char* pszFuncSig, char* pszFmt, ...)
    {
        char msg[256] = { 0 };
    
        va_list vArgList;
        va_start(vArgList, pszFmt);
        vsnprintf(msg, 256, pszFmt, vArgList);
        va_end(vArgList);
    
        time_t now = time(NULL);
        struct tm* tmstr = localtime(&now);
        char content[512] = { 0 };
        /*sprintf(content, "[%04d-%02d-%02d %02d:%02d:%02d][%s][0x%04x][%d]
    ",
            tmstr->tm_year + 1900,
            tmstr->tm_mon + 1,
            tmstr->tm_mday,
            tmstr->tm_hour,
            tmstr->tm_min,
            tmstr->tm_sec,
            pszLevel,
            std::this_thread::get_id(),
            lineNo
            );*/
    
        sprintf_s(content, ARRAYSIZE(content), "[%04d-%02d-%02d %02d:%02d:%02d][%s][0x%04x][%s:%d %s]%s
    ",
            tmstr->tm_year + 1900,
            tmstr->tm_mon + 1,
            tmstr->tm_mday,
            tmstr->tm_hour,
            tmstr->tm_min,
            tmstr->tm_sec,
            pszLevel,
            GetCurrentThreadId(),
            pszFile,
            lineNo,
            pszFuncSig,
            msg);
    
        {
            std::lock_guard<std::mutex> guard(mutex_);
            queue_.emplace_back(content);
        }
    
        cv_.notify_one();
    }
    
    void Logger::threadfunc()
    {
        if (fp_ == NULL)
            return;
    
        while (!exit_)
        {
            //写日志  
            std::unique_lock<std::mutex> guard(mutex_);
            while (queue_.empty())
            {
                if (exit_)
                    return;
    
                cv_.wait(guard);
            }
    
            //写日志  
            const std::string& str = queue_.front();
    
            fwrite((void*)str.c_str(), str.length(), 1, fp_);
            fflush(fp_);
            queue_.pop_front();
        }
    }
    View Code
    111
  • 相关阅读:
    Azure 3月新公布(二)
    亲,「广撒网」的营销方式你还没厌倦吗?
    Azure进阶攻略 | 下载还是在浏览器直接打开,MIME说了算!
    5步玩转Power BI Embedded,老司机全程带路解析
    手握不同媒体的数据,接下来该干些什么?
    cmake教程
    翻译Lanlet2
    pugixml 1.9 manual解读(部分)
    U盘无法拔出的解决办法
    Function Pointers in C
  • 原文地址:https://www.cnblogs.com/zwj-199306231519/p/13820712.html
Copyright © 2011-2022 走看看