栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

CPP服务器03--日志类实现

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

CPP服务器03--日志类实现

日志类实现 功能需求:
- 允许多个线程同时写,但刷入磁盘必须保持相对顺序
实现思路:
  • 组件:

    • 阻塞队列 std::unique_ptr queue_;
    • 刷盘线程 std::unique_ptrstd::thread writeThread_;
    • 日志容器 Buffer buff_;
    • 互斥锁 std::mutex mtx_;
  • 思路:

    • 单例模式实现一个日志类;
      • 外界调用不断添加日志进阻塞队列queue_;
      • 写线程不断从阻塞队列取日志刷盘;
    • 互斥锁用来控制对buff_的访问
头文件
#ifndef LOG_H
#define LOG_H

#include "blockqueue.hpp"
#include "../buffer/buffer.h"

#include 
#include 
#include 
#include 
#include 
#include            // vastart va_end
#include 
#include          //mkdir

class Log {
public:
    static Log* Instance(); //静态实例
    static void FlushLogThread();//刷盘线程传函
    
    void init(int level, const char* path = "./log",
                int maxQueueCapacity = 1024);
    void write(int level, const char *format,...);//写入阻塞队列
    void flush();//清空队列
    int GetLevel();
    
private:
    Log();
    void AppendLogLevelTitle_(int level);
    virtual ~Log();
    void AsyncWrite_();

private:
    const char* path_;
    int level_;

    FILE* fp_;
    Buffer buff_;

    std::unique_ptr> queue_; 
    std::unique_ptr writeThread_;
    std::mutex mtx_;

};

#define LOG_base(level, format, ...) 
    do {
        Log* log = Log::Instance();
        if (log->GetLevel() <= level) {
            log->write(level, format, ##__VA_ARGS__); 
            log->flush();
        }
    } while(0);

#define LOG_DEBUG(format, ...) do {LOG_base(0, format, ##__VA_ARGS__)} while(0);
#define LOG_INFO(format, ...) do {LOG_base(1, format, ##__VA_ARGS__)} while(0);
#define LOG_WARN(format, ...) do {LOG_base(2, format, ##__VA_ARGS__)} while(0);
#define LOG_ERROR(format, ...) do {LOG_base(3, format, ##__VA_ARGS__)} while(0);

#endif //LOG_H
源文件
#include "log.h"

using namespace std;

Log::Log() {
    writeThread_ = nullptr;
    queue_ = nullptr;
    fp_ = nullptr;
}

Log::~Log() {
    if(writeThread_ && writeThread_->joinable()) {
        while(! queue_->empty()) {
             queue_->flush();
        };
         queue_->Close();
        writeThread_->join();
    }
    if(fp_) {
        lock_guard locker(mtx_);
        flush();
        fclose(fp_);
    }
}

int Log::GetLevel() {
    lock_guard locker(mtx_);
    return level_;
}

void Log::init(int level = 1, const char* path, int maxQueueSize) {
    level_ = level;
    path_ = path;

    unique_ptr> newQueue(new BlockQueue);
    queue_ = move(newQueue);
    std::unique_ptr NewThread(new thread(FlushLogThread));
    writeThread_ = move(NewThread);

    time_t timer = time(nullptr);
    struct tm *sysTime = localtime(&timer);
    struct tm t = *sysTime;
    char fileName[256] = {0};
    snprintf(fileName, 256 - 1, "%s/%04d_%02d_%02d%s", 
            path_, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, ".log");

    lock_guard locker(mtx_);
    buff_.RetrieveAll();
    if(fp_) { 
        flush();
        fclose(fp_); 
    }

    fp_ = fopen(fileName, "a");
    if(fp_ == nullptr) {
        mkdir(path_, 0777);
        fp_ = fopen(fileName, "a");
    } 
    assert(fp_ != nullptr);
}

void Log::write(int level, const char *format, ...) {
    struct timeval now = {0, 0};
    gettimeofday(&now, nullptr);
    time_t tSec = now.tv_sec;
    struct tm *sysTime = localtime(&tSec);
    struct tm t = *sysTime;
    va_list vaList;

    unique_lock locker(mtx_);
    
    int n = snprintf(buff_.BeginWrite(), 128, "%d-%02d-%02d %02d:%02d:%02d.%06ld ",
                t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
                t.tm_hour, t.tm_min, t.tm_sec, now.tv_usec);
                
    buff_.HasWritten(n);
    AppendLogLevelTitle_(level);

    va_start(vaList, format);
    int m = vsnprintf(buff_.BeginWrite(), buff_.WritableBytes(), format, vaList);
    va_end(vaList);

    buff_.HasWritten(m);
    buff_.Append("n", 2);

    if(queue_ && ! queue_->full()) {
            queue_->push(buff_.RetrieveAllToStr());
    } else {
        fputs(buff_.Peek(), fp_);
    }
    buff_.RetrieveAll();
}

void Log::AppendLogLevelTitle_(int level) {
    switch(level) {
    case 0:
        buff_.Append("[debug]: ", 9);
        break;
    case 1:
        buff_.Append("[info] : ", 9);
        break;
    case 2:
        buff_.Append("[warn] : ", 9);
        break;
    case 3:
        buff_.Append("[error]: ", 9);
        break;
    default:
        buff_.Append("[info] : ", 9);
        break;
    }
}

void Log::flush() {
    queue_->flush(); 
    fflush(fp_);
}

void Log::AsyncWrite_() {
    string str = "";
    while( queue_->pop(str)) {
        lock_guard locker(mtx_);
        fputs(str.c_str(), fp_);
    }
}

Log* Log::Instance() {
    static Log inst;
    return &inst;
}

void Log::FlushLogThread() {
    Log::Instance()->AsyncWrite_();
}
测试代码1
#include "../log/blockqueue.hpp"
#include "../log/log.h"

#include "pthread.h"
#include 
#include 
#include 



void * writeLog(void *arg)
{
    srand(time(0));
    for(int i=0; i<5; i++)
    {
        sleep(rand() % 3);
        LOG_DEBUG("DEBUG: %ld>>%d",pthread_self(), i);
        LOG_INFO("INFO: %ld>>%d",pthread_self(), i);
        LOG_WARN("WARN: %ld>>%d",pthread_self(), i);
        LOG_ERROR("ERROR: %ld>>%d",pthread_self(), i);
    }
    
}


int main()
{
    int logLevel = 0;
    Log::Instance()->init(logLevel, "./log");

    for(int i=0; i<3; i++)
    {
        pthread_t tid;
        pthread_create(&tid, NULL, writeLog, NULL);
        pthread_join(tid, NULL);// log析构函数中用到了join方法
    }

    return 0;
}
引用
  • 源代码:https://github.com/Aged-cat/WebServer
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/277549.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号