Browse Source

日志log类

Jeff Wang 3 năm trước cách đây
mục cha
commit
0a4dca4a43

+ 84 - 0
TCLTools/TCLTools/CritSection.h

@@ -0,0 +1,84 @@
+#ifndef __CRITSECTION_20160221__
+#define __CRITSECTION_20160221__
+
+// ÁÙ½çÖµ;
+class ThreadSection
+{
+public:
+	ThreadSection(){
+		HRESULT hr = Init();
+		(hr);
+	}
+
+	~ThreadSection(){
+		DeleteCriticalSection(&_CriticalSection);
+	}
+
+	bool Lock()
+	{
+		bool result = false;
+		__try
+		{
+			EnterCriticalSection(&_CriticalSection);
+			result = true;
+		}
+		__except (STATUS_NO_MEMORY == GetExceptionCode())
+		{
+		}
+		return result;
+	}
+
+	bool Unlock()
+	{
+		bool result = false;
+		__try
+		{
+			LeaveCriticalSection(&_CriticalSection);
+			result = true;
+		}
+		__except (STATUS_NO_MEMORY == GetExceptionCode())
+		{
+		}
+		return result;
+	}
+
+private:
+	HRESULT Init() throw()
+	{
+		HRESULT hRes = E_FAIL;
+		__try
+		{
+			InitializeCriticalSection(&_CriticalSection);
+			hRes = S_OK;
+		}
+		__except (STATUS_NO_MEMORY == GetExceptionCode())
+		{
+			hRes = E_OUTOFMEMORY;
+		}
+		return hRes;
+	}
+
+	ThreadSection(const ThreadSection & tSection);
+	ThreadSection &operator=(const ThreadSection & tSection);
+	CRITICAL_SECTION _CriticalSection;
+};
+
+
+class AutoThreadSection
+{
+public:
+	AutoThreadSection(IN ThreadSection* pSection){
+		_pSection = pSection;
+		_pSection->Lock();
+	}
+
+	~AutoThreadSection(){
+		_pSection->Unlock();
+	}
+private:
+	AutoThreadSection(const AutoThreadSection & tSection);
+	AutoThreadSection &operator=(const AutoThreadSection & tSection);
+	ThreadSection * _pSection;
+};
+
+#endif //__CRITSECTION_20160221__

+ 194 - 0
TCLTools/TCLTools/log.cpp

@@ -0,0 +1,194 @@
+#include "stdafx.h"
+#include "log.h"
+//#include <sys/file.h>
+//#include <stdarg.h>
+#include <time.h>
+#include <stdlib.h>
+//#include <string.h>
+//#include <errno.h>
+#include <io.h>
+//#include <sys/stat.h>
+#include <direct.h>
+
+#ifndef R_OK
+#define R_OK 4
+#endif
+
+#ifndef W_OK
+#define W_OK 2
+#endif
+
+#ifndef X_OK
+#define X_OK 6
+#endif
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+
+Log_Writer WARN_W;
+Log_Writer INFO_W;
+char Log_Writer::m_buffer[_LOG_BUFFSIZE] = {0};
+
+bool log_init(LogLevel l, const char* p_modulename, const char* p_logdir)
+{
+    //如果路径存在文件夹,则判断是否存在
+    if (_access(p_logdir, 0) == -1)
+    {
+        if (mkdir(p_logdir ) < 0)
+            fprintf(stderr, "create folder failed\n");
+    }
+    char _location_str[MAX_PATH];
+    _snprintf(_location_str, MAX_PATH, "%s\\%s.log", p_logdir, p_modulename);	
+    INFO_W.loginit(l, _location_str);
+    _snprintf(_location_str, MAX_PATH, "%s\\%s.error", p_logdir, p_modulename);
+    //warning级别以上日志去WARN_W  去向由宏决定的 请见macro_define.h
+    if(l > LL_WARNING)
+        WARN_W.loginit(l, _location_str);
+    else
+        WARN_W.loginit(LL_WARNING, _location_str);
+    return true;
+}
+
+const char* Log_Writer::logLevelToString(LogLevel l) 
+{
+    switch ( l ) 
+    {
+    case LL_DEBUG:
+        return "DEBUG";
+    case LL_TRACE:
+        return "TRACE";
+    case LL_NOTICE:
+        return "NOTICE";
+    case LL_WARNING:
+        return "WARN" ;
+    case LL_ERROR:
+        return "ERROR";
+    default:
+        return "UNKNOWN";
+    }
+}
+
+bool Log_Writer::checklevel(LogLevel l)
+{
+    if(l >= m_system_level)
+        return true;
+    else
+        return false;
+}
+
+bool Log_Writer::loginit(LogLevel l, const  char *filelocation, bool append, bool issync)
+{
+    MACRO_RET(NULL != fp, false);
+    m_system_level = l;
+    m_isappend = append; 
+    m_issync = issync; 
+    if(strlen(filelocation) >= (sizeof(m_filelocation) -1))
+    {
+        fprintf(stderr, "the path of log file is too long:%d limit:%d\n", strlen(filelocation), sizeof(m_filelocation) -1);
+        exit(0);
+    }
+    //本地存储filelocation  以防止在栈上的非法调用调用
+    strncpy(m_filelocation, filelocation, sizeof(m_filelocation));
+    m_filelocation[sizeof(m_filelocation) -1] = '\0';
+
+    if('\0' == m_filelocation[0])
+    {
+        fp = stdout;
+        fprintf(stderr, "now all the running-information are going to put to stderr\n");
+        return true;
+    }
+
+    fp = fopen(m_filelocation, append ? "a":"w");
+    if(fp == NULL)
+    {
+        fprintf(stderr, "cannot open log file,file location is %s\n", m_filelocation);
+        exit(0);
+    }
+    //setvbuf (fp, io_cached_buf, _IOLBF, sizeof(io_cached_buf)); //buf set _IONBF  _IOLBF  _IOFBF
+    setvbuf (fp,  (char *)NULL, _IOLBF, _LOG_BUFFSIZE);
+    fprintf(stderr, "now all the running-information are going to the file %s\n", m_filelocation);
+    return true;
+}
+
+int Log_Writer::premakestr(char* m_buffer, LogLevel l)
+{
+    time_t now;
+    now = time(&now);;
+    struct tm vtm = *localtime(&now);
+
+    // 获取今年年份;
+    //__time64_t gmt = time(NULL); // 获取当前日历时间(1900-01-01开始的Unix时间戳);
+    //struct tm gmtm = { 0 };
+    //localtime_s(&gmtm, &gmt); // 时间戳转成本地时间;
+
+    return _snprintf(m_buffer, _LOG_BUFFSIZE, "%s: %02d-%02d %02d:%02d:%02d ", logLevelToString(l),
+        vtm.tm_mon + 1, vtm.tm_mday, vtm.tm_hour, vtm.tm_min, vtm.tm_sec);
+}
+
+bool Log_Writer::log(LogLevel l, char* logformat, ...)
+{
+    MACRO_RET(!checklevel(l), false);
+    int _size;
+    int prestrlen = 0;
+
+    memset(m_buffer, 0, _LOG_BUFFSIZE);
+    char * star = m_buffer;
+    prestrlen = premakestr(star, l);
+    star += prestrlen;
+
+    va_list args = NULL;
+    va_start(args, logformat);
+    _size = _vstprintf_s(star, _LOG_BUFFSIZE - prestrlen, logformat, args);//_vstprintf_s _vsntprintf
+    va_end(args);
+
+    if(NULL == fp)
+        fprintf(stderr, "%s", m_buffer);
+    else
+        _write(m_buffer, prestrlen + _size);
+    return true;
+}
+
+bool Log_Writer::_write(char *_pbuffer, int len)
+{
+    if(0 != _access(m_filelocation, W_OK))
+    {	
+        AutoThreadSection _cs(&m_mutex);
+        //锁内校验 access 看是否在等待锁过程中被其他线程loginit了  避免多线程多次close 和init
+        if(0 != _access(m_filelocation, W_OK))
+        {
+            logclose();
+            loginit(m_system_level, m_filelocation, m_isappend, m_issync);
+        }
+    }
+
+    if(1 == fwrite(_pbuffer, len, 1, fp)) //only write 1 item
+    {
+        if(m_issync)
+            fflush(fp);
+        *_pbuffer='\0';
+    }
+    else 
+    {
+        int x = errno;
+        fprintf(stderr, "Failed to write to logfile. errno:%s    message:%s", strerror(x), _pbuffer);
+        return false;
+    }
+    return true;
+}
+
+LogLevel Log_Writer::get_level()
+{
+    return m_system_level; 
+}
+
+bool Log_Writer::logclose()
+{
+    if(fp == NULL)
+        return false;
+    fflush(fp);
+    fclose(fp);
+    fp = NULL;
+    return true;
+}
+

+ 74 - 0
TCLTools/TCLTools/log.h

@@ -0,0 +1,74 @@
+#ifndef   _MACRO_LogModule
+#define   _MACRO_LogModule
+
+#include <stdio.h>
+#include "log_macro.h"
+#include "CritSection.h"
+
+/* 每个线程的buffer size*/
+#define   _LOG_BUFFSIZE  1024*1024*4
+/* 当前进程的 Stream IO buffer size*/
+#define   _SYS_BUFFSIZE  1024*1024*8
+/* log 文件字符串路径最大长度*/
+#define	  _LOG_PATH_LEN  250
+/* 日志对应的模块名*/
+#define   _LOG_MODULE_LEN 32
+
+typedef  enum LogLevel {  
+    LL_DEBUG = 1,
+    LL_TRACE = 2,
+    LL_NOTICE = 3, 
+    LL_WARNING = 4, 
+    LL_ERROR = 5,
+}LogLevel;
+
+
+class Log_Writer
+{
+public:
+    Log_Writer()
+    {
+        m_system_level = LL_NOTICE;
+        fp = NULL;
+        m_issync = false;
+        m_isappend = true;
+        m_filelocation[0] ='\0'; 
+    }
+    ~Log_Writer(){
+        logclose();
+    }
+    bool loginit(LogLevel l, const  char *filelocation, bool append = true, bool issync = true);
+    bool log(LogLevel l,char *logformat,...);
+    LogLevel get_level();
+    bool logclose();
+private:
+    const char* logLevelToString(LogLevel l);
+    bool checklevel(LogLevel l);
+    int premakestr(char* m_buffer, LogLevel l);
+    bool _write(char *_pbuffer, int len);
+private:
+    enum LogLevel m_system_level;
+    FILE* fp;
+    bool m_issync;
+    bool m_isappend;
+    char m_filelocation[MAX_PATH];
+    ThreadSection m_mutex;
+    static char m_buffer[_LOG_BUFFSIZE];
+    //The __thread specifier may be applied to any global, file-scoped static, function-scoped static, 
+    //or static data member of a class. It may not be applied to block-scoped automatic or non-static data member
+    //in the log  scence,It's safe!!!!
+    //一言以蔽之,此场景不用担心__thread带来资源leak,同时也不用担心多个Log_Writer会干扰,
+    //因为一个线程同一时间只有一个Log_Writer在干活,干完之后m_buffer就reset了
+    //所以即便一个线程用户多个Log_Write串行(因为一个线程内的运行态只有串行) 也是线程安全的!!!
+};
+
+extern Log_Writer WARN_W;
+extern Log_Writer INFO_W;
+
+/**
+* LogLevel 日志级别
+* p_modulename 模块名 如mysql
+* p_logdir  日志输出目录
+* */
+bool log_init(LogLevel l, const char* p_modulename, const char* p_logdir);
+#endif

+ 64 - 0
TCLTools/TCLTools/log_macro.h

@@ -0,0 +1,64 @@
+#ifndef  _MACRO_DEFINE
+#define  _MACRO_DEFINE
+//============basic===================
+/*
+VC6是不支持可变参数宏的,VC2005支持。
+
+使用如下:
+#define TRACE(pszFormat, ...) \
+CTL_CommonLogger::Output(LOGGER, LEVEL_TRACE, pszFormat, __VA_ARGS__); 
+
+其中,__VA_ARGS__就是不定参数。
+
+注意:直接这样,是没法编译通过的,因为这个宏要求编译器是VC2002(VC7.0)以上的版本,也就是说,_MSC_VER宏应该是1400以上的值。所以,使用前,应该加上如下的定义:
+#ifndef _MSC_VER  
+#define _MSC_VER 1600 
+#endif      
+1600也就是VC8.0。
+
+
+补充:改一下。CTL_CommonLogger::Output是一个类的静态成员函数。
+类似,可以使用下面的写法:
+#define PRINT(x, ...)    \
+print(x, __VA_ARGS__); 
+
+print函数的原型:int Print(char * x, ...);
+
+不定参数函数的实现,可以参考Windows的TRACE宏或ATLTRACE宏。
+*/
+
+#define LOG_ERROR(log_fmt, log_arg,...) \
+        WARN_W.log(LL_ERROR,"[line:%d][%s] " log_fmt "\n", __LINE__, __FUNCTION__, log_arg, __VA_ARGS__); 
+
+#define LOG_WARN(log_fmt, log_arg,...) \
+        WARN_W.log(LL_WARNING,"[line:%d][%s] " log_fmt "\n", __LINE__, __FUNCTION__, log_arg, __VA_ARGS__); 
+
+#define LOG_NOTICE(log_fmt, log_arg, ...) \
+        INFO_W.log(LL_NOTICE,"[line:%d][%s] " log_fmt "\n", __LINE__, __FUNCTION__, log_arg, __VA_ARGS__); 
+
+#define LOG_TRACE(log_fmt, log_arg,...) \
+        INFO_W.log(LL_TRACE,"[line:%d][%s] " log_fmt "\n", __LINE__, __FUNCTION__, log_arg, __VA_ARGS__); 
+
+#define LOG_DEBUG(log_fmt, log_arg,...) \
+        INFO_W.log(LL_DEBUG,"[line:%d][%s] " log_fmt "\n",  __LINE__, __FUNCTION__, log_arg, __VA_ARGS__); 
+
+//============extend===================
+#define MACRO_RET(condition, return_val) {\
+    if (condition) {\
+        return return_val;\
+    }\
+}
+
+#define MACRO_WARN(condition, log_fmt, log_arg,...) {\
+    if (condition) {\
+        LOG_WARN( log_fmt, ##log_arg);\
+    }\
+}
+
+#define MACRO_WARN_RET(condition, return_val, log_fmt, log_arg,...) {\
+    if ((condition)) {\
+        LOG_WARN( log_fmt, ##log_arg);\
+		return return_val;\
+    }\
+}
+#endif