64,671
社区成员
发帖
与我相关
我的任务
分享
#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__
#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);
}
}
}
#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;
}
#include "logging.h"
LOG_INFO()<<"this is an information." << "这是一条信息";
LOG(LS_ERROR) << "this is an error." << "这是一个错误信息";
LOG_ERR(LS_WARNING) << "这里有打印出当前错误信息";
// LOG_GLEM
// LOG_GLE