C程序日志类---利用读写锁重写

上一篇日志,写到了C程序下面logger日志类的实现,但是由于有缺陷,并且日志文件看起来比较麻烦(同时创建了几个日志文件)。后面在看到读写锁的机制后,觉得可以利用读写锁来重写这个日志类。

关键在于所有日志输出都加读锁,只有在日志大小达到了限制,才进行写锁加锁,修改相关信息。

(这里我一直有个误解,就是其实进行锁操作应该是很快的,关键在于加锁之后,临界区的代码执行职能处于单个线程执行,而其他等待的情况,导致多线程速度变慢,之前的版本一直坚持不做锁操作,直到某种条件满足,是源于这个误解)

关键代码如下:

    //任何些日子操作都加读锁
    pthread_rwlock_rdlock(&rwLock);
    int currentSize = ftell(fpIn);
    if(currentSize>=logger::fileCapability){
        //解读锁,以便能进行写操作,修改fp指向
        pthread_rwlock_unlock(&rwLock);
        //加写锁
        pthread_rwlock_wrlock(&rwLock);
        if(ftell(fpIn)>=logger::fileCapability){
            fclose(fpIn);
            char tmp[10] = {0};
            sprintf(tmp,"%d",index);
            std::string newName = fileName+"_"+tmp;
            rename(fileName.c_str(),newName.c_str());
            fpIn = fopen(fileName.c_str(),"w");
            index ++;
            if(index>=fileNumLimit)
                index = 1;
        }
        //解写锁
        pthread_rwlock_unlock(&rwLock);
        //加读锁
        pthread_rwlock_rdlock(&rwLock);
        printf("thread:%lu current err file fp is %x, size is %d\n", pthread_self(), fpIn, currentSize);
        //output to stdout
        fprintf(stdout, "%s:[TIME: %s] [MSG: %s]\n", preFixStr.c_str(), timestamp.c_str(), bufferMsg.c_str());
        fprintf(fpIn, "%s:[TIME: %s] [MSG: %s]\n", preFixStr.c_str(), timestamp.c_str(), bufferMsg.c_str());
        //解读锁
        pthread_rwlock_unlock(&rwLock);
    }else{
        printf("thread:%lu current err file fp is %x, size is %d\n", pthread_self(), fpIn, currentSize);
        //output to stdout
        fprintf(stdout, "%s:[TIME: %s] [MSG: %s]\n", preFixStr.c_str(), timestamp.c_str(), bufferMsg.c_str());
        fprintf(fpIn, "%s:[TIME: %s] [MSG: %s]\n", preFixStr.c_str(), timestamp.c_str(), bufferMsg.c_str());
        pthread_rwlock_unlock(&rwLock);
    }
再附上完整代码:

logger_v2.h

#ifndef LOGGER_H__
#define LOGGER_H__

#include <string>
#include <stdlib.h>
#include <vector>

#include <pthread.h>

struct FileInfo{
    std::string fileBaseName;
    FILE* fp;
    FileInfo(){
	fileBaseName = "";
        fp = NULL;
    }
};

class logger{

public:
    //错误日志文件名配置名称
    static const std::string LOGGER_ERROR_FILE_NAME_CONF_NAME;
    //信息日志文件名配置名称
    static const std::string LOGGER_INFO_FILE_NAME_CONF_NAME;
    //调试日志文件名配置名称
    static const std::string LOGGER_DEBUG_FILE_NAME_CONF_NAME;
    //单个文件大小配置名称
    static const std::string LOGGER_SINGLE_FILE_CAPA_CONF_NAME;
    //保存的文件个数配置名称
    static const std::string LOGGER_FILE_NUM_CONF_NAME;
    //输出日志的级别设定配置名称
    static const std::string LOGGER_LEVEL_CONF_NAME;

private:
    //错误日志文件名和文件描述符
    static std::string errFileName;
    static FILE* errFp;
    //信息日志文件名和文件描述符
    static std::string infoFileName;
    static FILE* infoFp;
    //调试日志文件名和文件描述符
    static std::string debugFileName;
    static FILE* debugFp;

    static unsigned char currentIndexOfErr;
    static unsigned char currentIndexOfInfo;
    static unsigned char currentIndexOfDebug;

    //单个日志文件大小
    static int fileCapability;
    //log 文件个数
    static int fileNumLimit;
    //输出的日志级别( error, info, debug )
    static std::string loggerLevel;
    static int prefixSize;

    //读写锁
    static pthread_rwlock_t rwLock;

public:
    static bool init(const std::string configFileName);
public:
    void info(const char* format, ...);
    void error(const char* format, ...);
    void debug(const char* format, ...); 
private:
    void writeLog(std::string &preFixStr, std::string& fileName, FILE* &fpIn, unsigned char& index, std::string &bufferMsg);
};

#endif

logger_v2.cpp

#include "logger_v2.h"
#include <time.h>
#include <sys/time.h>
#include "confReader.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>

#define MAX_MSG_LEN 1024 
#define TIMESTAMP_LEN 100

const std::string logger::LOGGER_ERROR_FILE_NAME_CONF_NAME = "error_file_name";
const std::string logger::LOGGER_INFO_FILE_NAME_CONF_NAME = "info_file_name";
const std::string logger::LOGGER_DEBUG_FILE_NAME_CONF_NAME = "debug_file_name";
const std::string logger::LOGGER_SINGLE_FILE_CAPA_CONF_NAME = "single_file_capability";
const std::string logger::LOGGER_FILE_NUM_CONF_NAME = "file_num";
const std::string logger::LOGGER_LEVEL_CONF_NAME = "log_level";

std::string logger::errFileName = "";
FILE* logger::errFp = NULL;
std::string logger::infoFileName = "";
FILE* logger::infoFp = NULL;
std::string logger::debugFileName = "";
FILE* logger::debugFp = NULL;

unsigned char logger::currentIndexOfErr = 1;
unsigned char logger::currentIndexOfInfo = 1;
unsigned char logger::currentIndexOfDebug = 1;

int logger::fileCapability = 512;
int logger::fileNumLimit = 1;
std::string logger::loggerLevel = "error";
int logger::prefixSize = 0;

pthread_rwlock_t logger::rwLock;

bool logger::init(const std::string configFileName){
    ConfReader reader;
    reader.readConfFile(configFileName);

    errFileName = reader.getParameterValue(logger::LOGGER_ERROR_FILE_NAME_CONF_NAME);
    infoFileName = reader.getParameterValue(logger::LOGGER_INFO_FILE_NAME_CONF_NAME);
    debugFileName = reader.getParameterValue(logger::LOGGER_DEBUG_FILE_NAME_CONF_NAME);

    std::string singleFileCapabilityStr = reader.getParameterValue(logger::LOGGER_SINGLE_FILE_CAPA_CONF_NAME);
    fileCapability = atoi(singleFileCapabilityStr.c_str());
    std::string fileNumLimitStr = reader.getParameterValue(logger::LOGGER_FILE_NUM_CONF_NAME);
    fileNumLimit = atoi(fileNumLimitStr.c_str());

    errFp = NULL;
    currentIndexOfErr = 1;
    infoFp = NULL;
    currentIndexOfInfo = 1;
    debugFp = NULL;
    currentIndexOfDebug = 1;
   
    //set log level
    loggerLevel = reader.getParameterValue(logger::LOGGER_LEVEL_CONF_NAME);
    prefixSize = strlen("ERROR:[TIME: ] [MSG: ]\n");
    pthread_rwlock_init(&rwLock,NULL);
    return true;
}

static std::string getCurrentFullTime(){

    char timestamp[TIMESTAMP_LEN];
    
    struct timeval time;
    gettimeofday(&time, NULL);
    struct tm* tm_t = localtime(&time.tv_sec);
    strftime(timestamp , sizeof(timestamp),"%F.%H:%M:%S",tm_t);
    
    return timestamp;
    
}

void logger::writeLog(std::string& preFixStr, std::string& fileName, FILE* &fpIn, unsigned char& index, std::string& bufferMsg){
    std::string timestamp = getCurrentFullTime();    
    pthread_rwlock_rdlock(&rwLock);
    //检查是否文件已经打开
    if(fpIn==NULL){
	pthread_rwlock_unlock(&rwLock);
	pthread_rwlock_wrlock(&rwLock);
	if(fpIn==NULL){
	    fpIn = fopen(fileName.c_str(),"w"); 
	}
	pthread_rwlock_unlock(&rwLock);
        pthread_rwlock_rdlock(&rwLock);

    }
    int currentSize = ftell(fpIn);
    if(currentSize>=logger::fileCapability){
        //解读锁,以便能进行写操作,修改fp指向
        pthread_rwlock_unlock(&rwLock);
        //加写锁
	pthread_rwlock_wrlock(&rwLock);
        if(ftell(fpIn)>=logger::fileCapability){
	    fclose(fpIn);
	    char tmp[10] = {0};
	    sprintf(tmp,"%d",index);
	    std::string newName = fileName+"_"+tmp;
            rename(fileName.c_str(),newName.c_str());
	    fpIn = fopen(fileName.c_str(),"w");
	    index ++;
            if(index>=fileNumLimit)
		index = 1;
	}
        //解写锁
        pthread_rwlock_unlock(&rwLock);
        //加读锁
        pthread_rwlock_rdlock(&rwLock);
        printf("thread:%lu current err file fp is %x, size is %d\n", pthread_self(), fpIn, currentSize);
	//output to stdout
	fprintf(stdout, "%s:[TIME: %s] [MSG: %s]\n", preFixStr.c_str(), timestamp.c_str(), bufferMsg.c_str());
        fprintf(fpIn, "%s:[TIME: %s] [MSG: %s]\n", preFixStr.c_str(), timestamp.c_str(), bufferMsg.c_str());
  	//解读锁
        pthread_rwlock_unlock(&rwLock);
    }else{
        printf("thread:%lu current err file fp is %x, size is %d\n", pthread_self(), fpIn, currentSize); 
        //output to stdout
        fprintf(stdout, "%s:[TIME: %s] [MSG: %s]\n", preFixStr.c_str(), timestamp.c_str(), bufferMsg.c_str());
	fprintf(fpIn, "%s:[TIME: %s] [MSG: %s]\n", preFixStr.c_str(), timestamp.c_str(), bufferMsg.c_str());
        pthread_rwlock_unlock(&rwLock);
    }
}

void logger::error(const char* format, ...){
    char buf[ MAX_MSG_LEN + 1];
    memset(buf, 0x00, MAX_MSG_LEN + 1);
    if ( logger::loggerLevel != "error" && logger::loggerLevel != "info" && logger::loggerLevel != "debug"){
        return;
    }

    va_list ap;
    va_start(ap, format);
    vsnprintf( buf, MAX_MSG_LEN, format, ap);
    va_end(ap);

    std::string type = "ERROR";
    std::string bufferMsg = buf;
    writeLog(type, errFileName, errFp, currentIndexOfErr, bufferMsg);
}

void logger::info(const char* format, ...){
    char buf[ MAX_MSG_LEN + 1];
    memset(buf, 0x00, MAX_MSG_LEN + 1);
    if ( logger::loggerLevel != "info" && logger::loggerLevel != "debug"){
        return;
    }

    va_list ap;
    va_start(ap, format);
    vsnprintf( buf, MAX_MSG_LEN, format, ap);
    va_end(ap);

    std::string type = "INFO";
    std::string bufferMsg = buf;
    writeLog(type, infoFileName, infoFp, currentIndexOfInfo, bufferMsg);
}

void logger::debug(const char* format, ...){
    char buf[ MAX_MSG_LEN + 1];
    memset(buf, 0x00, MAX_MSG_LEN + 1);
    if ( logger::loggerLevel != "debug"){
        return;
    }

    va_list ap;
    va_start(ap, format);
    vsnprintf( buf, MAX_MSG_LEN, format, ap);
    va_end(ap);

    std::string type = "DEBUG";
    std::string bufferMsg = buf;
    writeLog(type, debugFileName, debugFp, currentIndexOfDebug, bufferMsg);
}

#ifdef LOGGER_TEST

void* printLog(void* arg){

    int i = 200000000,j=0;

    logger myLogger;
    while(i--){

        myLogger.info("thread id:%lu testLog:%s:%d",pthread_self(), "test1",j++);

    }

    return NULL;
}

int main(int argc, char* argv[]){
    if(argc!=2){
        printf("please input pragram, configFileName\n");
        return -1;
    }

    logger::init(argv[1]);

    pthread_t id[3];
    for(int i=0;i<3;i++){
        pthread_create(&(id[i]), NULL, printLog, NULL);
    }

    for(int i=0;i<3;i++){
        pthread_join(id[i], NULL);
    }

    return 0;
}

#endif



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值