Ubuntu/linux c开发(3)日志模块
linux 自己编写日志log模块
·
开发服务程序日志是必不可少的,又不想用log4g就自己写了个日志模块。下载连接走线程池,里面包含了日志,没要积分。
先看实现结果:
直接上代码,有问题可以留言。
1、头文件.h
#ifndef _LOG_MODEL_H_
#define _LOG_MODEL_H_
#include <string.h>
#include <string>
#include <stdio.h>
#include <pthread.h>
#include <queue>
#include <stdarg.h>
#include <unistd.h>
using namespace std;
/* 红色对应 CRITICAL 与 ERROR log
* 黄色对应 WARNING log
* 绿色对应 INFO log
* 蓝色对应 DEBUG log
*/
#define LOCAL_RED "\033[31;1m"
#define LOCAL_YELLOW "\033[0;33m"
#define LOCAL_GREEN "\033[0;32m"
#define LOCAL_BULE "\033[0;34m"
#define LOCAL_END "\033[0m"
#define LOGSIEZ_1024 1024 // 日志大小
#define OPEN_LOG 1 // 声明是否打开日志输出
#define LOG_LEVEL LOGLEVEL_DEBUG // 声明当前程序的日志等级状态,只输出等级等于或高于该值的内容
#define LOG_SAVE 1 // 可补充日志保存功能
#define Sleep(nMills) usleep(1000*nMills) 毫秒延时函数 仿window Sleep()
#define ONE_MILLIS_1_MS 1
#define MaxFileSize_2M 2*1024*1024 //日志存储大小
typedef unsigned short DWORD;
typedef enum{ // 日志等级,越往下等级越高
LOGLEVEL_DEBUG = 0,
LOGLEVEL_INFO,
LOGLEVEL_WARN,
LOGLEVEL_ERROR,
}E_LOGLEVEL;
//日志结构体
typedef struct _LOG_INFO
{
string strLogInfo; //日志内容
int nLogLev; //日志等级
_LOG_INFO()
{
strLogInfo = "";
nLogLev = LOGLEVEL_INFO;
}
}LOG_INFO;
/*
*
* 功能:日志组包。
* 返回值:
* 参1:日志等级,E_LOGLEVEL
* 参2:日志产生的文件。
* 参3:日志产生的方法名称。
* 参4:日志所在行数。
* 参5:日志内容。
*/
void log_Model(const int nLevel, const char* szFile, const char* szFun, const int nLine, const char *szfmt, ...);
// 宏定义,隐藏形参
//#define DP_LOG(nLevel, fmt...) log_Model(nLevel, __FILE__ ,__FUNCTION__, __LINE__, fmt)
//修改成流形式 类似cout<<"123"<<"123"; 输出 123123
#define DP_LOG(nLevel, message){ \
std::ostringstream t_stream;\
t_stream << message;\
log_Model(nLevel, __FILE__ ,__FUNCTION__, __LINE__, (const char *)t_stream.str().c_str()) ;\
}
#define SWITCH_PRINT(fmt,...) do { \
if (fmt >= LOG_LEVEL) { \
switch (fmt) { \
case LOGLEVEL_DEBUG: \
printf(LOCAL_BULE); \
break; \
case LOGLEVEL_INFO: \
printf(LOCAL_GREEN); \
break; \
case LOGLEVEL_WARN: \
printf(LOCAL_YELLOW); \
break; \
case LOGLEVEL_ERROR: \
printf(LOCAL_RED); \
break; \
default: \
printf(LOCAL_GREEN); \
break;\
} \
printf(__VA_ARGS__); \
printf(LOCAL_END); \
} \
} while(0)
class CLogModel
{
public:
CLogModel();
~CLogModel();
/*
* 功能:初始化日志对象。
* 返回值:初始化成功返回true /失败返回false
* 参1:日志路径
*/
bool IniLog(std::string strFilePath);
private:
/*
* 功能:创建日志文件,保存文件句柄。
* 返回值:创建成功返回true /失败返回false
* 参1:日志路径
*/
bool CreateFileAndGetHandle(std::string strFilePath);
private:
FILE* m_logfile;
std::string m_lastFileName;
std::string m_lastFilePath;
bool m_bQuitThread;
protected:
//日志管理线程
static void* LogManageThreadProc(void* p);
//线程内核
DWORD ManageCoreRun();
};
#endif
2、源文件.cpp
#include "logModel.h"
#include <time.h>
//日志队列
typedef queue<LOG_INFO> Que_LogInfo;
Que_LogInfo g_LogInfo;
//日志锁
pthread_mutex_t g_LogMutex;
//全局锁初始化标志
bool g_IniFlag=true;
//仿win32 GetTickCount接口
unsigned long GetCurrentSeconds()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}
char *logLevelGet(const int nLevel){ // 得到当前输入等级level的字符串
if(nLevel == LOGLEVEL_DEBUG){
return (char*)"DEBUG";
}else if (nLevel == LOGLEVEL_INFO ){
return (char*)"INFO";
}else if (nLevel == LOGLEVEL_WARN ){
return (char*)"WARN";
}else if (nLevel == LOGLEVEL_ERROR ){
return (char*)"ERROR";
}else{
return (char*)"UNKNOWN";
}
}
void log_Model(const int nLevel, const char* szFile, const char* szFun, const int nLine, const char *szfmt, ...){ // 日志输出函数
char szLog[LOGSIEZ_1024];
LOG_INFO temp_log;
//define修改这里直接赋值
//va_list arg;
//va_start(arg, szfmt);
//char szBuf[LOGSIEZ_1024]; // 创建缓存字符数组
//vsnprintf(szBuf, sizeof(szBuf), szfmt, arg); // 赋值 ftm 格式的 arg 到 buf
//va_end(arg);
sprintf(szLog,"[%s %s][%s]\t[%s] [%s] [%d]: %s \n",\
__DATE__,__TIME__ ,logLevelGet(nLevel), szFile,szFun, nLine, szBuf);
{//将数据放到日志队列 等待写日志
pthread_mutex_lock(&g_LogMutex);
temp_log.nLogLev = nLevel;
temp_log.strLogInfo = szLog;
g_LogInfo.push(temp_log);
pthread_mutex_unlock(&g_LogMutex);
}
}
CLogModel::CLogModel()
{
m_logfile = NULL;
m_lastFileName = "";
m_lastFilePath = "";
m_bQuitThread = false;
//g_LogMutex全局锁初始化
if(g_IniFlag){
pthread_mutex_init(&g_LogMutex, NULL);g_IniFlag=false;
}
}
CLogModel::~CLogModel()
{
}
bool CLogModel::IniLog(std::string strFilePath)
{
m_lastFilePath = strFilePath;
if(CreateFileAndGetHandle(strFilePath)) {
m_bQuitThread=true;
pthread_t hThread;
m_bQuitThread = true;
bool ret = pthread_create(&hThread, NULL, LogManageThreadProc, this);
if (ret != false){
printf("hThread err");
return false;
}
return true;
}
printf("CreateFileAndGetHandle err");
return false;
}
bool CLogModel::CreateFileAndGetHandle(std::string strFilePath)
{
char fname[256];
memset(fname,0,sizeof(fname));
char longtime[200];
time_t t;
time(&t);
struct tm local = {0};
localtime_r(&t, &local);
sprintf(longtime,"%04d-%02d-%02d/", local.tm_year+1900,
local.tm_mon+1, local.tm_mday);
sprintf(fname,"%s/%s", strFilePath.c_str(),longtime);
if(access(fname,0)!=0)
{
char cmdstr[256] = {0};
sprintf(cmdstr,"mkdir -p %s",fname);
system(cmdstr);
}
sprintf(fname,"%s%02d_%02d_%02d.log", fname,local.tm_hour, local.tm_min, local.tm_sec);
bool retdate = false;
unsigned long t_tick = GetCurrentSeconds();
while(1)
{
m_logfile = fopen(fname, "ab");
if(m_logfile)
{
m_lastFileName = fname;
retdate=true;
break;
}
sleep(1);
//超过2.5s 认定超时
if (GetCurrentSeconds()-t_tick>2500)
{
break;
}
}
return retdate;
}
void* CLogModel::LogManageThreadProc(void* p)
{
CLogModel* pThis = (CLogModel*)p;
pThis->ManageCoreRun();
return NULL;
}
DWORD CLogModel::ManageCoreRun()
{
//当前秒数
DWORD dwTimeStart = 0;
while (m_bQuitThread)
{
Sleep(ONE_MILLIS_1_MS*10);
pthread_mutex_lock(&g_LogMutex);
int nQueLogCon = g_LogInfo.size();
pthread_mutex_unlock(&g_LogMutex);
if (nQueLogCon<=0)
continue;
LOG_INFO temp_log;
pthread_mutex_lock(&g_LogMutex);
temp_log = g_LogInfo.front();
g_LogInfo.pop();
pthread_mutex_unlock(&g_LogMutex);
if(temp_log.nLogLev >= LOG_LEVEL){ // 判断当前日志等级,与程序日志等级状态对比
//1、展示
if(OPEN_LOG){
SWITCH_PRINT(temp_log.nLogLev,temp_log.strLogInfo.c_str());
}
//2、存储
if (LOG_SAVE){
char showstr[LOGSIEZ_1024],showstr2[LOGSIEZ_1024];
//看具体存储编码做转化,可以参考之前的GB2312ToUTF8博客
//GB2312ToUTF8((char*)temp_log.strLogInfo.c_str(), strlen(temp_log.strLogInfo.c_str()), showstr2, sizeof(showstr2));
char longtime[200];
time_t t;
time(&t);
struct tm local = {0};
localtime_r(&t, &local);
sprintf(longtime,"%04d-%02d-%02d %02d:%02d:%02d", local.tm_year+1900,
local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
m_logfile = fopen(m_lastFileName.c_str(), "ab");
if(m_logfile){
if (ftell(m_logfile) < MaxFileSize_2M) {// 判断文件大小
//日期时间
const char* pTemp = longtime;
fwrite(pTemp, 1, strlen(pTemp), m_logfile);
fwrite(" ", 1, 1, m_logfile);
//内容
fwrite(temp_log.strLogInfo.c_str(), 1, strlen(temp_log.strLogInfo.c_str()), m_logfile);
fwrite(":", 1, 1, m_logfile);
fwrite(showstr2, 1, strlen(showstr2), m_logfile);
fwrite(" \r\n", 1, 3, m_logfile);
fclose(m_logfile);
}
else{
fclose(m_logfile);
m_logfile = NULL;
//超过5M 关闭当前,重新创建开一个flie
CreateFileAndGetHandle(m_lastFilePath);
//
//可以在这里做删除之前的日志..
}
}
else
{
CreateFileAndGetHandle(m_lastFilePath);
}
}
}
}
return 0;
}
3、main
#include <iostream>
#include <unistd.h>
#include "logModel.h"
using namespace std;
int main(int argc, char *argv[])
{
char sz[] = "Hello, World!"; //Hover mouse over "sz" while debugging to see its contents
cout << sz << endl; //<================= Put a breakpoint here
CLogModel m_log;
m_log.IniLog("log");
DP_LOG(LOGLEVEL_DEBUG,"this debug");
DP_LOG(LOGLEVEL_INFO,"this info");
DP_LOG(LOGLEVEL_WARN,"this warn");
DP_LOG(LOGLEVEL_ERROR,"this err");
DP_LOG(4,"this 4");
while(1)
{
usleep(10000);
}
return 0;
}
更多推荐
已为社区贡献1条内容
所有评论(0)