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;
}

一个小巧的C++Log输出到文件类

一个小巧的C++Log输出到文件类 (转) 作者:wangyin159 http://www.cnblogs.com/mazhenyu/p/4139352.html ...
  • wangtiewei
  • wangtiewei
  • 2016年07月05日 10:56
  • 2369

一个小巧的C++Log输出到文件类 (转)

http://www.cnblogs.com/mazhenyu/p/4139352.html 一个小巧的C++Log输出到文件类 (转)   http://blog.csdn...
  • wangyin159
  • wangyin159
  • 2015年07月01日 08:49
  • 890

C++开源log选用

C++比较有名的日志类库公有log4cpp 、log4cxx、 log4cplus、glog,其中log4cpp log4xx最近两年都没有更新了。只有log4cplus和glog在更新,因此在log...
  • caowei880123
  • caowei880123
  • 2016年06月30日 15:00
  • 1045

用C++实现一个Log系统

提要最近在写一些C++的图形代码,在调试和测试过程中都会需要在终端打印一些信息出来。之前的做法是直接用std::cout这样做其实非常的麻烦,每次都要打很多的字母还有特殊符号,除去我要打印的内容,还需...
  • qp120291570
  • qp120291570
  • 2015年12月13日 01:14
  • 3063

C++遍历日志log目录,并提取数据进行分析

1 前言   我们经常在编写软件的时候,需要加载log文件来记录程序运行过程中可能会出现的bug,或者记录一些重要的运行信息。一旦一个目录下生成很多log文件后,实际上我们管理与分析还是需要费一些时...
  • FX677588
  • FX677588
  • 2017年07月31日 23:26
  • 608

如何将C++的标准输出打印到logcat中

D在default状态下调用printf 等std C/C++ 接口输出的log不会被打印到eclipse的logcat中, 但是android提供了__android_log_print 这个函数可...
  • wys7250578
  • wys7250578
  • 2014年01月28日 14:24
  • 2105

C/C++log日志库比较

事实上,在C的世界里面没有特别好的日志函数库(就像JAVA里面的的log4j,或者C++的log4cxx)。C程序员都喜欢用自己的轮子。printf就是个挺好的轮子,但没办法通过配置改变日志的格式或者...
  • gatieme
  • gatieme
  • 2016年01月28日 23:21
  • 16630

C++实现简易log日志系统

1.log日志的作用 在软件开发周期中,不管是前台还是后台,系统一般会采用一个持久化的日志系统来记录运行情况。 在代码中嵌入log代码信息,主要记录下列信息: (1)记录系统运行异常信息。 (2)...
  • K346K346
  • K346K346
  • 2015年07月16日 10:46
  • 7590

自己写的C++日志类log

主要功能是在服务器运行的时候可以打印日志到日志文件中,主要运用到的知识点有线程, 线程锁,条件变量,STL的deque。大致思路是这样的:             这个类提供一个接口,可以直接调用他...
  • u012314708
  • u012314708
  • 2016年08月05日 17:12
  • 3063

C++打印日志输出文件

做后台服务程序很多情况下都需要打印日志输出,我这里有简单的C++使用的打印日志输出文件可以直接复制粘贴使用,很方便,直接贴代码了。#ifndef NETDATALOG_H #define NETDAT...
  • huangyifei_1111
  • huangyifei_1111
  • 2016年08月06日 10:51
  • 5493
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ log
举报原因:
原因补充:

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