C/C++ logging日志类分享

china_jeffery
博客专家认证
2013-02-02 09:49:59
参考google的libjingle库,写了一个简单的日志记录类,功能相对来说不是很复杂,但是很方便实用,现拿来分享,欢迎个位拍砖。

logging.h:

#ifndef CLASSES_LOGGING_H__
#define CLASSES_LOGGING_H__

#include <iostream>
#include <iomanip>
#include <sstream>
#include <Windows.h>

// A macro to disallow the evil copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)


// Note that the non-standard LoggingSeverity aliases exist because they are
// still in broad use. The meanings of the levels are:
// LS_SENSITIVE: Information which should only be logged with the consent
// of the user, due to privacy concerns.
// LS_VERBOSE: This level is for data which we do not want to appear in the
// normal debug log, but should appear in diagnostic logs.
// LS_INFO: Chatty level used in debugging for all sorts of things, the default
// in debug builds.
// LS_WARNING: Something that may warrant investigation.
// LS_ERROR: Something that should not have occurred.
enum LoggingSeverity
{
LS_SENSITIVE,
LS_VERBOSE,
LS_INFO,
LS_WARNING,
LS_ERROR,
INFO = LS_INFO,
WARNING = LS_WARNING,
LERROR = LS_ERROR
};

// LogErrorContext assists in interpreting the meaning of an error value.
// ERRCTX_ERRNO: the value was read from global 'errno'
// ERRCTX_HRESULT: the value is a Windows HRESULT
enum LogErrorContext
{
ERRCTX_NONE,
ERRCTX_ERRNO,
ERRCTX_HRESULT
};

class LogMessage
{
public:
LogMessage(const char* file, // source file name,is not the log filename.
int line,
LoggingSeverity sev,
LogErrorContext err_ctx = ERRCTX_NONE,
int err = 0,
const char* module = NULL);

~LogMessage();


std::ostream& stream()
{
return print_stream_;
}


// Timestamps begin with program execution, but can be reset with this
// function for measuring the duration of an activity, or to synchronize
// timestamps between multiple instances.
static void ResetTimestamps();

private:
// These assist in formatting some parts of the debug output.
static const char* Describe(LoggingSeverity sev);
static const char* DescribeFile(const char* file);
static long TimeDiff(unsigned long later, unsigned long earlier);
static bool TimeIsBetween(unsigned long later, unsigned long middle, unsigned long earlier);

// The ostream that buffers the formatted message before output
std::ostringstream print_stream_;


// The severity level of this message
LoggingSeverity severity_;

// String data generated in the constructor, that should be appended to
// the message before output.
std::string extra_;

// The timestamp at which logging started.
static unsigned long start_;

HANDLE hFile_;

DISALLOW_EVIL_CONSTRUCTORS(LogMessage);
};


#define LOG_INFO() LogMessage(__FILE__, __LINE__, LS_INFO).stream()

#define LOG(sev) LogMessage(__FILE__, __LINE__, sev).stream()


// The _F version prefixes the message with the current function name.
#define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": "


// PLOG and LOG_ERR attempt to provide a string description of an errno derived
// error. LOG_ERR reads errno directly, so care must be taken to call it before
// errno is reset.
#define PLOG(sev, err) LogMessage(__FILE__, __LINE__, sev, ERRCTX_ERRNO, err).stream()

#define LOG_ERR(sev) LogMessage(__FILE__, __LINE__, sev, ERRCTX_ERRNO, errno).stream()

// LOG_GLE(M) attempt to provide a string description of the HRESULT returned
// by GetLastError. The second variant allows searching of a dll's string
// table for the error description.
#define LOG_GLE(sev) LogMessage(__FILE__, __LINE__, sev, \
ERRCTX_HRESULT, GetLastError()).stream()

#define LOG_GLEM(sev, mod) LogMessage(__FILE__, __LINE__, sev, \
ERRCTX_HRESULT, GetLastError(), mod) \
.stream()
#endif // CLASSES_LOGGING_H__



logging.cpp:

#include "logging.h"

extern "C" BOOL WINAPI IsDebuggerPresent(void);

// Program start time
unsigned long LogMessage::start_ = GetTickCount();

LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev,
LogErrorContext err_ctx, int err, const char* module)
: severity_(sev)
{
unsigned long time = TimeDiff(GetTickCount(), start_);
print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 60000)
<< ":" << std::setw(2) << (time %60000)/1000
<< ":" << std::setw(3) << time %1000 << std::setfill(' ')
<< "] ";

DWORD id = GetCurrentThreadId();
print_stream_ << "[0x" << std::setfill('0') << std::setw(8)
<< std::hex << id << std::dec << "] ";


print_stream_ << Describe(sev) << "(" << DescribeFile(file)
<< ":" << line << "): ";

if (err_ctx != ERRCTX_NONE)
{
std::ostringstream tmp;
tmp << "[0x" << std::setfill('0') << std::hex << std::setw(8) << err << "]";
switch (err_ctx)
{
case ERRCTX_ERRNO:
{
tmp << " " << strerror(err);
break;
}
case ERRCTX_HRESULT:
{
char msgbuf[256]={0};
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
HMODULE hmod = GetModuleHandleA(module);
if (hmod)
flags |= FORMAT_MESSAGE_FROM_HMODULE;
if (DWORD len = FormatMessageA(
flags, hmod, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), NULL))
{
while ((len > 0) &&
isspace(static_cast<unsigned char>(msgbuf[len-1])))
{
msgbuf[--len] = 0;
}
tmp << " " << msgbuf;
}
break;
}

default:
break;
}
extra_ = tmp.str();
}
}


LogMessage::~LogMessage()
{
if (!extra_.empty())
print_stream_ << " : " << extra_;
print_stream_ << "\r\n";
const std::string& str = print_stream_.str();

static bool debugger_present = (IsDebuggerPresent() != FALSE);
if (debugger_present)
{
OutputDebugStringA(str.c_str());
}
else
{
hFile_ = ::CreateFileA("Test.txt",GENERIC_WRITE,0,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
if(INVALID_HANDLE_VALUE != hFile_)
{
unsigned long written=0L;

::SetFilePointer (hFile_, 0, NULL, FILE_END);
::WriteFile(hFile_, str.data(), str.size(), &written, 0);

FlushFileBuffers(hFile_);
::CloseHandle(hFile_);
}
else
{
hFile_ = NULL;
}
}
}



void LogMessage::ResetTimestamps()
{
start_ = GetTickCount();
}



const char* LogMessage::Describe(LoggingSeverity sev)
{
switch (sev)
{
case LS_SENSITIVE: return "Sensitive";
case LS_VERBOSE: return "Verbose";
case LS_INFO: return "Info";
case LS_WARNING: return "Warning";
case LS_ERROR: return "Error";
default: return "<unknown>";
}
}

const char* LogMessage::DescribeFile(const char* file)
{
const char* end1 = ::strrchr(file, '/');
const char* end2 = ::strrchr(file, '\\');
if (!end1 && !end2)
return file;
else
return (end1 > end2) ? end1 + 1 : end2 + 1;
}


bool LogMessage::TimeIsBetween(unsigned long later, unsigned long middle, unsigned long earlier)
{
if (earlier <= later)
{
return ((earlier <= middle) && (middle <= later));
}
else
{
return !((later < middle) && (middle < earlier));
}
}


long LogMessage::TimeDiff(unsigned long later, unsigned long earlier)
{
unsigned long LAST = 0xFFFFFFFF;
unsigned long HALF = 0x80000000;
if (TimeIsBetween(earlier + HALF, later, earlier))
{
if (earlier <= later)
{
return static_cast<long>(later - earlier);
}
else
{
return static_cast<long>(later + (LAST - earlier) + 1);
}
}
else
{
if (later <= earlier)
{
return -static_cast<long>(earlier - later);
}
else
{
return -static_cast<long>(earlier + (LAST - later) + 1);
}
}
}



libjingle库下载地址:http://download.csdn.net/detail/china_jeffery/5038519
...全文
740 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
maeol 2013-12-13
  • 打赏
  • 举报
回复
代码很怪,没见过这种写法,研究一下,谢谢分享!!
makill_kill 2013-11-29
  • 打赏
  • 举报
回复
碎炎 2013-02-06
  • 打赏
  • 举报
回复
用google的glog的路过
翅膀又硬了 2013-02-05
  • 打赏
  • 举报
回复
使用方法挺新颖,我喜欢
Defonds 2013-02-05
  • 打赏
  • 举报
回复
Thanks for sharing
china_jeffery 2013-02-05
  • 打赏
  • 举报
回复
不要做咸鱼 2013-02-04
  • 打赏
  • 举报
回复
mark & quote
疯狂的红豆 2013-02-04
  • 打赏
  • 举报
回复
mark了,LZ辛苦了
赵4老师 2013-02-04
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
    #include <windows.h>
    #include <io.h>
#else
    #include <unistd.h>
    #include <sys/time.h>
    #include <pthread.h>
    #define  CRITICAL_SECTION   pthread_mutex_t
    #define  _vsnprintf         vsnprintf
#endif
//Log{
#define MAXLOGSIZE 20000000
#define MAXLINSIZE 16000
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
static char logstr[MAXLINSIZE+1];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
#ifdef WIN32
void Lock(CRITICAL_SECTION *l) {
    EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
    LeaveCriticalSection(l);
}
#else
void Lock(CRITICAL_SECTION *l) {
    pthread_mutex_lock(l);
}
void Unlock(CRITICAL_SECTION *l) {
    pthread_mutex_unlock(l);
}
#endif
void LogV(const char *pszFmt,va_list argp) {
    struct tm *now;
    struct timeb tb;

    if (NULL==pszFmt||0==pszFmt[0]) return;
    _vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);
    ftime(&tb);
    now=localtime(&tb.time);
    sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
    sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );
    sprintf(mss,"%03d",tb.millitm);
    printf("%s %s.%s %s",datestr,timestr,mss,logstr);
    flog=fopen(logfilename1,"a");
    if (NULL!=flog) {
        fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
        if (ftell(flog)>MAXLOGSIZE) {
            fclose(flog);
            if (rename(logfilename1,logfilename2)) {
                remove(logfilename2);
                rename(logfilename1,logfilename2);
            }
        } else {
            fclose(flog);
        }
    }
}
void Log(const char *pszFmt,...) {
    va_list argp;

    Lock(&cs_log);
    va_start(argp,pszFmt);
    LogV(pszFmt,argp);
    va_end(argp);
    Unlock(&cs_log);
}
//Log}
int main(int argc,char * argv[]) {
    int i;
#ifdef WIN32
    InitializeCriticalSection(&cs_log);
#else
    pthread_mutex_init(&cs_log,NULL);
#endif
    for (i=0;i<10000;i++) {
        Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__);
    }
#ifdef WIN32
    DeleteCriticalSection(&cs_log);
#else
    pthread_mutex_destroy(&cs_log);
#endif
    return 0;
}
zslInSz 2013-02-04
  • 打赏
  • 举报
回复
mark一下,感谢楼主分享
lee_鹿游原 2013-02-04
  • 打赏
  • 举报
回复
收藏了,多向楼主学习。
ChinaTek 2013-02-04
  • 打赏
  • 举报
回复
收藏了,楼主辛苦了
赵4老师 2013-02-04
  • 打赏
  • 举报
回复
这个帖子分页有点古怪!
china_jeffery 2013-02-03
  • 打赏
  • 举报
回复
自己顶了。。。
chuachua66 2013-02-02
  • 打赏
  • 举报
回复
鼓励一下,发扬勤动手的好习惯!现在越来越懒了,唉~~~~~~~
sublimepan 2013-02-02
  • 打赏
  • 举报
回复
楼主辛苦了
china_jeffery 2013-02-02
  • 打赏
  • 举报
回复
使用方式:

#include "logging.h"


LOG_INFO()<<"this is an information." << "这是一条信息";
LOG(LS_ERROR) << "this is an error." << "这是一个错误信息";
LOG_ERR(LS_WARNING) << "这里有打印出当前错误信息";
// LOG_GLEM
// LOG_GLE

65,189

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧