C++ log

原创 2015年07月09日 15:20:14

以下代码摘自SSDB。
最近项目使用boost log 发现有些问题,于是在
SSDB源码里找到了下面的log类,使用起来不错。大家可以学习一下文件操作和变长参数函数实现。

log.h

/*
Copyright (c) 2012-2014 The SSDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
#ifndef UTIL_LOG_H
#define UTIL_LOG_H

#include <inttypes.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include <fcntl.h>
#include <assert.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>

class Logger{
    public:
        static const int LEVEL_NONE     = (-1);
        static const int LEVEL_MIN      = 0;
        static const int LEVEL_FATAL    = 0;
        static const int LEVEL_ERROR    = 1;
        static const int LEVEL_WARN     = 2;
        static const int LEVEL_INFO     = 3;
        static const int LEVEL_DEBUG    = 4;
        static const int LEVEL_TRACE    = 5;
        static const int LEVEL_MAX      = 5;

        static int get_level(const char *levelname);
    private:
        FILE *fp;
        char filename[PATH_MAX];
        int level_;
        pthread_mutex_t *mutex;

        uint64_t rotate_size;
        struct{
            uint64_t w_curr;
            uint64_t w_total;
        }stats;

        void rotate();
        void threadsafe();
    public:
        Logger();
        ~Logger();

        int level(){
            return level_;
        }

        void set_level(int level){
            this->level_ = level;
        }

        int open(FILE *fp, int level=LEVEL_DEBUG, bool is_threadsafe=false);
        int open(const char *filename, int level=LEVEL_DEBUG,
            bool is_threadsafe=false, uint64_t rotate_size=0);
        void close();

        int logv(int level, const char *fmt, va_list ap);

        int trace(const char *fmt, ...);
        int debug(const char *fmt, ...);
        int info(const char *fmt, ...);
        int warn(const char *fmt, ...);
        int error(const char *fmt, ...);
        int fatal(const char *fmt, ...);
};


int log_open(FILE *fp, int level=Logger::LEVEL_DEBUG, bool is_threadsafe=false);
int log_open(const char *filename, int level=Logger::LEVEL_DEBUG,
    bool is_threadsafe=false, uint64_t rotate_size=0);
int log_level();
void set_log_level(int level);
int log_write(int level, const char *fmt, ...);


#ifdef NDEBUG
    #define log_trace(fmt, args...) do{}while(0)
#else
    #define log_trace(fmt, args...) \
        log_write(Logger::LEVEL_TRACE, "%s(%d): " fmt, __FILE__, __LINE__, ##args)
#endif

#define log_debug(fmt, args...) \
    log_write(Logger::LEVEL_DEBUG, "%s(%d): " fmt, __FILE__, __LINE__, ##args)
#define log_info(fmt, args...)  \
    log_write(Logger::LEVEL_INFO,  "%s(%d): " fmt, __FILE__, __LINE__, ##args)
#define log_warn(fmt, args...)  \
    log_write(Logger::LEVEL_WARN,  "%s(%d): " fmt, __FILE__, __LINE__, ##args)
#define log_error(fmt, args...) \
    log_write(Logger::LEVEL_ERROR, "%s(%d): " fmt, __FILE__, __LINE__, ##args)
#define log_fatal(fmt, args...) \
    log_write(Logger::LEVEL_FATAL, "%s(%d): " fmt, __FILE__, __LINE__, ##args)


#endif

log.cpp

/*
Copyright (c) 2012-2014 The SSDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
#include "log.h"

static Logger logger;

int log_open(FILE *fp, int level, bool is_threadsafe){
    return logger.open(fp, level, is_threadsafe);
}

int log_open(const char *filename, int level, bool is_threadsafe, uint64_t rotate_size){
    return logger.open(filename, level, is_threadsafe, rotate_size);
}

int log_level(){
    return logger.level();
}

void set_log_level(int level){
    logger.set_level(level);
}

int log_write(int level, const char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);
    int ret = logger.logv(level, fmt, ap);
    va_end(ap);
    return ret;
}

/*****/

Logger::Logger(){
    fp = stdout;
    level_ = LEVEL_DEBUG;
    mutex = NULL;

    filename[0] = '\0';
    rotate_size = 0;
    stats.w_curr = 0;
    stats.w_total = 0;
}

Logger::~Logger(){
    if(mutex){
        pthread_mutex_destroy(mutex);
        free(mutex);
    }
    this->close();
}

void Logger::threadsafe(){
    if(mutex){
        pthread_mutex_destroy(mutex);
        free(mutex);
        mutex = NULL;
    }
    mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
    pthread_mutex_init(mutex, NULL);
}

int Logger::open(FILE *fp, int level, bool is_threadsafe){
    this->fp = fp;
    this->level_ = level;
    if(is_threadsafe){
        this->threadsafe();
    }
    return 0;
}

int Logger::open(const char *filename, int level, bool is_threadsafe, uint64_t rotate_size){
    if(strlen(filename) > PATH_MAX - 20){
        fprintf(stderr, "log filename too long!");
        return -1;
    }
    strcpy(this->filename, filename);

    FILE *fp;
    if(strcmp(filename, "stdout") == 0){
        fp = stdout;
    }else if(strcmp(filename, "stderr") == 0){
        fp = stderr;
    }else{
        fp = fopen(filename, "a");
        if(fp == NULL){
            return -1;
        }

        struct stat st;
        int ret = fstat(fileno(fp), &st);
        if(ret == -1){
            fprintf(stderr, "fstat log file %s error!", filename);
            return -1;
        }else{
            this->rotate_size = rotate_size;
            stats.w_curr = st.st_size;
        }
    }
    return this->open(fp, level, is_threadsafe);
}

void Logger::close(){
    if(fp != stdin && fp != stdout){
        fclose(fp);
    }
}

void Logger::rotate(){
    fclose(fp);
    char newpath[PATH_MAX];
    time_t time;
    struct timeval tv;
    struct tm *tm;
    gettimeofday(&tv, NULL);
    time = tv.tv_sec;
    tm = localtime(&time);
    sprintf(newpath, "%s.%04d%02d%02d-%02d%02d%02d",
        this->filename,
        tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
        tm->tm_hour, tm->tm_min, tm->tm_sec);

    //printf("rename %s => %s\n", this->filename, newpath);
    int ret = rename(this->filename, newpath);
    if(ret == -1){
        return;
    }
    fp = fopen(this->filename, "a");
    if(fp == NULL){
        return;
    }
    stats.w_curr = 0;
}

int Logger::get_level(const char *levelname){
    if(strcmp("trace", levelname) == 0){
        return LEVEL_TRACE;
    }
    if(strcmp("debug", levelname) == 0){
        return LEVEL_DEBUG;
    }
    if(strcmp("info", levelname) == 0){
        return LEVEL_INFO;
    }
    if(strcmp("warn", levelname) == 0){
        return LEVEL_WARN;
    }
    if(strcmp("error", levelname) == 0){
        return LEVEL_ERROR;
    }
    if(strcmp("fatal", levelname) == 0){
        return LEVEL_FATAL;
    }
    if(strcmp("none", levelname) == 0){
        return LEVEL_NONE;
    }
    return LEVEL_DEBUG;
}

inline static const char* level_name(int level){
    switch(level){
        case Logger::LEVEL_FATAL:
            return "[FATAL] ";
        case Logger::LEVEL_ERROR:
            return "[ERROR] ";
        case Logger::LEVEL_WARN:
            return "[WARN ] ";
        case Logger::LEVEL_INFO:
            return "[INFO ] ";
        case Logger::LEVEL_DEBUG:
            return "[DEBUG] ";
        case Logger::LEVEL_TRACE:
            return "[TRACE] ";
    }
    return "";
}

#define LEVEL_NAME_LEN  8
#define LOG_BUF_LEN     4096

int Logger::logv(int level, const char *fmt, va_list ap){
    if(logger.level_ < level){
        return 0;
    }

    char buf[LOG_BUF_LEN];
    int len;
    char *ptr = buf;

    time_t time;
    struct timeval tv;
    struct tm *tm;
    gettimeofday(&tv, NULL);
    time = tv.tv_sec;
    tm = localtime(&time);
    /* %3ld 在数值位数超过3位的时候不起作用, 所以这里转成int */
    len = sprintf(ptr, "%04d-%02d-%02d %02d:%02d:%02d.%03d ",
        tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
        tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec/1000));
    if(len < 0){
        return -1;
    }
    ptr += len;

    memcpy(ptr, level_name(level), LEVEL_NAME_LEN);
    ptr += LEVEL_NAME_LEN;

    int space = sizeof(buf) - (ptr - buf) - 10;
    len = vsnprintf(ptr, space, fmt, ap);
    if(len < 0){
        return -1;
    }
    ptr += len > space? space : len;
    *ptr++ = '\n';
    *ptr = '\0';

    len = ptr - buf;
    // change to write(), without locking?
    if(this->mutex){
        pthread_mutex_lock(this->mutex);
    }
    fwrite(buf, len, 1, this->fp);
    fflush(this->fp);

    stats.w_curr += len;
    stats.w_total += len;
    if(rotate_size > 0 && stats.w_curr > rotate_size){
        this->rotate();
    }
    if(this->mutex){
        pthread_mutex_unlock(this->mutex);
    }

    return len;
}

int Logger::trace(const char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);
    int ret = logger.logv(Logger::LEVEL_TRACE, fmt, ap);
    va_end(ap);
    return ret;
}

int Logger::debug(const char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);
    int ret = logger.logv(Logger::LEVEL_DEBUG, fmt, ap);
    va_end(ap);
    return ret;
}

int Logger::info(const char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);
    int ret = logger.logv(Logger::LEVEL_INFO, fmt, ap);
    va_end(ap);
    return ret;
}

int Logger::warn(const char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);
    int ret = logger.logv(Logger::LEVEL_WARN, fmt, ap);
    va_end(ap);
    return ret;
}

int Logger::error(const char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);
    int ret = logger.logv(Logger::LEVEL_ERROR, fmt, ap);
    va_end(ap);
    return ret;
}

int Logger::fatal(const char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);
    int ret = logger.logv(Logger::LEVEL_FATAL, fmt, ap);
    va_end(ap);
    return ret;
}

相关文章推荐

log4cplus 一个开源的c++日志库

  • 2015年03月31日 23:15
  • 939KB
  • 下载

一个好用的log类(C++)

  • 2011年11月04日 12:26
  • 2KB
  • 下载

【2014年第五届蓝桥杯C/C++程序设计本科B组决赛 Log大侠(编程大题) 】

2014年第五届蓝桥杯C/C++程序设计本科B组决赛试题Log大侠 atm参加了速算训练班,经过刻苦修炼,对以2为底的对数算得飞快,人称Log大侠。 一天,Log大侠的好友 drd 有一些整数序列...

一个小巧的C++Log类

  • 2013年12月05日 17:04
  • 1KB
  • 下载

【问题汇总】在C/C++中使用Android Log导致编译失败的问题

在JNI中使用Android自带的Log日志功能,在编译时提示如下异常: kaizen@tuan800-inc:~/workspace_eclipse_1/im_pulltorefresh/MyJN...
  • manoel
  • manoel
  • 2014年09月22日 11:59
  • 2591

c++ 日志文件(log)记录库开源

  • 2017年08月13日 20:40
  • 1KB
  • 下载

Log.cpp c++

  • 2012年09月28日 12:33
  • 4KB
  • 下载

C++开源跨平台OJ系统判题核心FreeJudger(三)——log4cxx同时使用多个日志文件

C++开源跨平台OJ系统判题核心FreeJudger(三)——log4cxx同时使用多个日志文件 By 马冬亮(凝霜  Loki) 一个人的战争(http://blog.csdn.net/...

c++单元测试 log4

  • 2013年05月08日 11:34
  • 893KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ log
举报原因:
原因补充:

(最多只允许输入30个字)