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
...全文
663 16 打赏 收藏 转发到动态 举报
写回复
用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
附件是VS2010的工程,C++日志,谷歌的东西,很好用,也很强大哦! glog简介 Google glog是一个基于程序级记录日志信息的c++库,编程使用方式与c++的stream操作似,例: LOG(INFO) << "Found " << num_cookies << " cookies"; “LOG”宏为日志输出关键字,“INFO”为严重性程度。 主要支持功能: 1, 参数设置,以命令行参数的方式设置标志参数来控制日志记录行为; 2, 严重性分级,根据日志严重性分级记录日志; 3, 可有条件地记录日志信息; 4, 条件中止程序。丰富的条件判定宏,可预设程序终止条件; 5, 异常信号处理。程序异常情况,可自定义异常处理过程; 6, 支持debug功能。可只用于debug模式; 7, 自定义日志信息; 8, 线程安全日志记录方式; 9, 系统级日志记录; 10, google perror风格日志信息; 11, 精简日志字符串信息。 开源代码托管 开源代码地址:https://github.com/google/glog 其实官方开源代码已经有大量demo可以参考了,也提供了VS可以直接打开编译的项目。 如何使用 1:把glog文件夹拷贝到源代码目录 2:在工程设置中添加附加包含目录(glog\include;)和附加库目录(glog\lib;),在附件依赖项中添加对应lib文件,一一对应关系如下: MDd libglog32MDd.lib MD libglog32MD.lib MTd libglog32MTd.lib MT libglog32MT.lib 建议使用MDd和MD方式,带上对应的dll(在glog\bin目录,需要时拷贝到bin文件输出目录)可以避免使用MTd,MT引起的内存泄露是值得的。 #include #include using namespace std; //包含glog头文件,建议放在stdafx.h中 //#define GOOGLE_GLOG_DLL_DECL // 使用静态库的时候用这个,不过我测试静态库有内存泄露,所以不推荐使用静态库 #define GLOG_NO_ABBREVIATED_SEVERITIES #include "glog/logging.h" //获取当前程序的运行目录 string GetAppPathA() { char szExePath[MAX_PATH] = {0}; GetModuleFileNameA(NULL,szExePath,MAX_PATH); char *pstr = strrchr(szExePath,'\\'); memset(pstr+1,0,1); string strAppPath(szExePath); return strAppPath; } void main() { //glog初始化 google::InitGoogleLogging("重签程序"); string strLogPath = GetAppPathA().append("LogInfo\\"); CreateDirectoryA(strLogPath.c_str(),NULL); google::SetLogDestination(google::GLOG_INFO,strLogPath.c_str()); //功能测试 LOG(INFO)<<"log start...";//普通日志 LOG(WARNING)<<"Warning log";//警告日志 LOG(ERROR)<<"Error log";//错误日志 int i = 4; LOG_IF(INFO,i == 4)<<"Log if Test"; //以上就是我常用的几个日志函数了,当然还有很多更加强大的日志相关函数,大家如有有兴趣,可以参照官方给的示例使用, //开源代码地址:https://github.com/google/glog MessageBoxA(NULL,"Test Over",":)",MB_ICONINFORMATION); } 测试程序中,我使用的动态链接库方式。(Debug模式中代码生成为MDd,Release为MD)。lib是截止现在2015-11-04-21:35是最新的。采用VS2010编译,MTd,MT,MDd,MD方式编译在测试项目中都有提供。 博文地址: http://blog.csdn.net/sunflover454/article/details/49643625

64,671

社区成员

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

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