日志系统实现

一、使用原因:

    在实现高并发的服务器日志系统过程中,由于在工作线程中直接进行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
原文地址:https://www.cnblogs.com/zwj-199306231519/p/13820712.html