自己写的C++日志类log
2016-08-05 17:12
267 查看
主要功能是在服务器运行的时候可以打印日志到日志文件中,主要运用到的知识点有线程, 线程锁,条件变量,STL的deque。大致思路是这样的:
这个类提供一个接口,可以直接调用他,并且可以打印日志到日志文件中。但是不能影响到服务器的正常运行,也就是说不能进行大量的文件操作;
大致 实现流程:
对象初始化时候创建一个线程在后台读取队列,并将读到的数据写入到日志文件中,并在队列中删除这一数据;
接口处,每次写日志时,其实是将日志存到队列中去。交由后台线程写入到文件中。
整个程序难点:对于临界区的控制,即线程锁,条件变量的使用。
对deque的理解与使用。
在C++类内部实现类实例化;
下边上代码
log.h
#ifndef LOG_H
#define LOG_H
#include <stdio.h>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <pthread.h>
#include <deque>
using namespace std;
class Log
{
public:
static Log* get_instance()
{
static Log instance;
return &instance;
}
static void *flush_log_thread(void* args)
{
Log::get_instance()->async_write_log();
}
bool init(const char* file_name, int log_buf_size = 8192, int split_lines = 5000000, int max_queue_size = 0);
void write_log(int level, const char* format, ...);
void flush(void);
private:
Log();
virtual ~Log();
void *async_write_log()
{
string single_log;
while(1){
printf("%d\n",!m_log_queue.size());
if(!m_log_queue.size() )
{
pthread_mutex_lock(m_mutex);
{
pthread_cond_wait(m_cond, m_mutex);
single_log=m_log_queue.front();
fputs(single_log.c_str(), m_fp);
m_log_queue.pop_front();
pthread_mutex_unlock(m_mutex);
}
}else{
pthread_mutex_lock(m_mutex);
single_log=m_log_queue.front();
fputs(single_log.c_str(), m_fp);
m_log_queue.pop_front();
pthread_mutex_unlock(m_mutex);
}
}
printf("end\n");
}
private:
pthread_mutex_t *m_mutex;
pthread_cond_t *m_cond;
char dir_name[128];
char log_name[128];
int m_split_lines;
int m_log_buf_size;
long long m_count;
int m_today;
FILE *m_fp;
char *m_buf;
deque<string> m_log_queue;
bool m_is_async;
};
#define LOG_DEBUG(format, ...) Log::get_instance()->write_log(0, format, __VA_ARGS__)
#define LOG_INFO(format, ...) Log::get_instance()->write_log(1, format, __VA_ARGS__)
#define LOG_WARN(format, ...) Log::get_instance()->write_log(2, format, __VA_ARGS__)
#define LOG_ERROR(format, ...) Log::get_instance()->write_log(3, format, __VA_ARGS__)
#endif
log.cpp
*********************************************************/
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <stdarg.h>
#include "log.h"
#include <pthread.h>
using namespace std;
Log::Log()
{
m_count = 0;
m_mutex = new pthread_mutex_t;
m_cond = new pthread_cond_t;
m_is_async = false;
pthread_mutex_init(m_mutex, NULL);
}
Log::~Log()
{
if(m_fp != NULL)
{
fclose(m_fp);
}
pthread_cond_destroy(m_cond);
if(m_cond != NULL)
{
delete m_cond;
}
pthread_mutex_destroy(m_mutex);
if(m_mutex != NULL)
{
delete m_mutex;
}
}
bool Log::init(const char* file_name, int log_buf_size, int split_lines, int max_queue_size)
{
if(max_queue_size >= 1)
{
m_is_async = true;
// m_log_queue = new block_queue<string>(max_queue_size);
deque<string>(max_queue_size);
pthread_t tid;
pthread_create(&tid, NULL, flush_log_thread, NULL);
}
m_log_buf_size = log_buf_size;
m_buf = new char[m_log_buf_size];
memset(m_buf, '\0', sizeof(m_buf));
m_split_lines = split_lines;
time_t t = time(NULL);
struct tm* sys_tm = localtime(&t);
struct tm my_tm = *sys_tm;
const char *p = strrchr(file_name, '/');
char log_full_name[256] = {0};
if(p == NULL)
{
snprintf(log_full_name, 255, "%d_%02d_%02d_%s",my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday, file_name);
}
else
{
strcpy(log_name, p+1);
strncpy(dir_name, file_name, p - file_name + 1);
snprintf(log_full_name, 255, "%s%d_%02d_%02d_%s",dir_name, my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday, log_name );
}
m_today = my_tm.tm_mday;
m_fp = fopen(log_full_name, "a");
if(m_fp == NULL)
{
return false;
}
return true;
}
void Log::write_log(int level, const char* format, ...)
{
struct timeval now = {0,0};
gettimeofday(&now, NULL);
time_t t = now.tv_sec;
struct tm* sys_tm = localtime(&t);
struct tm my_tm = *sys_tm;
char s[16] = {0};
switch(level)
{
case 0 : strcpy(s, "[debug]:"); break;
case 1 : strcpy(s, "[info]:"); break;
case 2 : strcpy(s, "[warn]:"); break;
case 3 : strcpy(s, "[erro]:"); break;
default:
strcpy(s, "[info]:"); break;
}
pthread_mutex_lock(m_mutex);
m_count++;
if(m_today != my_tm.tm_mday || m_count % m_split_lines == 0) //everyday log
{
char new_log[256] = {0};
fflush(m_fp);
fclose(m_fp);
char tail[16] = {0};
snprintf(tail, 16, "%d_%02d_%02d_", my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday);
if(m_today != my_tm.tm_mday)
{
snprintf(new_log, 255, "%s%s%s", dir_name, tail, log_name);
m_today = my_tm.tm_mday;
m_count = 0;
}
else
{
snprintf(new_log, 255, "%s%s%s.%d", dir_name, tail, log_name, m_count/m_split_lines);
}
m_fp = fopen(new_log, "a");
}
pthread_mutex_unlock(m_mutex);
va_list valst;
va_start(valst, format);
string log_str;
pthread_mutex_lock(m_mutex);
int n = snprintf(m_buf, 48, "%d-%02d-%02d %02d:%02d:%02d.%06d %s ",
my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday,
my_tm.tm_hour, my_tm.tm_min, my_tm.tm_sec, now.tv_usec, s);
int m = vsnprintf(m_buf + n, m_log_buf_size-1, format, valst);
m_buf[n + m - 1] = '\n';
log_str = m_buf;
pthread_mutex_unlock(m_mutex);
if(m_is_async)// && !m_log_queue->full())
{
pthread_mutex_lock(m_mutex);
m_log_queue.push_back(log_str);
pthread_cond_broadcast(m_cond);
pthread_mutex_unlock(m_mutex);
}
else
{
pthread_mutex_lock(m_mutex);
fputs(log_str.c_str(), m_fp);
pthread_mutex_unlock(m_mutex);
}
va_end(valst);
}
void Log::flush(void)
{
pthread_mutex_lock(m_mutex);
fflush(m_fp);
pthread_mutex_unlock(m_mutex);
}
测试文件 main.cpp
#include "log.h"
void *f(void* args)
{
for(int i = 0;i < 10000; i++)
{
Log::get_instance()->write_log(1, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
Log::get_instance()->write_log(2, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
Log::get_instance()->write_log(3, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
LOG_INFO("%d", 123456789);
LOG_ERROR("%d", 123456789);
LOG_DEBUG("%d", 123456789);
LOG_WARN("%d", 123456789);
}
}
int main()
{
Log::get_instance()->init("./mylog.log", 100, 2000000, 10);
//Log::get_instance()->init("./mylog.log", 100, 2000000, 0);//synchronization model
// printf("11111111111111\n");
// sleep(1);
int i = 0;
Log::get_instance()->write_log(1, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
Log::get_instance()->write_log(2, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
Log::get_instance()->write_log(3, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
LOG_INFO("%d", 123456789);
LOG_ERROR("%d", 123456789);
LOG_DEBUG("%d", 123456789);
LOG_WARN("%d", 123456789);
pthread_t id;
for(int i = 0; i < 10; i++)
{
pthread_create(&id, NULL, f, NULL);
pthread_join(id,NULL);
}
//for(;;)
{
sleep(15);
Log::get_instance()->flush();
}
while(1);
// Log::get_instance()->put_log();
return 0;
}
别忘记:makefile
BIN := main
CFLAGS := -g -Wall -lpthread
CC := g++
SRCFILE := $(wildcard *.cpp)
OBJFILE := $(patsubst %.cpp,%.o,$(SRCFILE))
$(BIN): $(OBJFILE)
$(CC) $(CFLAGS) -o $(BIN) $(OBJFILE)
%.o:%.cpp
$(CC) $(CFLAGS) -c $< -o $@
clean :
rm -rf $(OBJFILE) ${BIN}
这个类提供一个接口,可以直接调用他,并且可以打印日志到日志文件中。但是不能影响到服务器的正常运行,也就是说不能进行大量的文件操作;
大致 实现流程:
对象初始化时候创建一个线程在后台读取队列,并将读到的数据写入到日志文件中,并在队列中删除这一数据;
接口处,每次写日志时,其实是将日志存到队列中去。交由后台线程写入到文件中。
整个程序难点:对于临界区的控制,即线程锁,条件变量的使用。
对deque的理解与使用。
在C++类内部实现类实例化;
下边上代码
log.h
#ifndef LOG_H
#define LOG_H
#include <stdio.h>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <pthread.h>
#include <deque>
using namespace std;
class Log
{
public:
static Log* get_instance()
{
static Log instance;
return &instance;
}
static void *flush_log_thread(void* args)
{
Log::get_instance()->async_write_log();
}
bool init(const char* file_name, int log_buf_size = 8192, int split_lines = 5000000, int max_queue_size = 0);
void write_log(int level, const char* format, ...);
void flush(void);
private:
Log();
virtual ~Log();
void *async_write_log()
{
string single_log;
while(1){
printf("%d\n",!m_log_queue.size());
if(!m_log_queue.size() )
{
pthread_mutex_lock(m_mutex);
{
pthread_cond_wait(m_cond, m_mutex);
single_log=m_log_queue.front();
fputs(single_log.c_str(), m_fp);
m_log_queue.pop_front();
pthread_mutex_unlock(m_mutex);
}
}else{
pthread_mutex_lock(m_mutex);
single_log=m_log_queue.front();
fputs(single_log.c_str(), m_fp);
m_log_queue.pop_front();
pthread_mutex_unlock(m_mutex);
}
}
printf("end\n");
}
private:
pthread_mutex_t *m_mutex;
pthread_cond_t *m_cond;
char dir_name[128];
char log_name[128];
int m_split_lines;
int m_log_buf_size;
long long m_count;
int m_today;
FILE *m_fp;
char *m_buf;
deque<string> m_log_queue;
bool m_is_async;
};
#define LOG_DEBUG(format, ...) Log::get_instance()->write_log(0, format, __VA_ARGS__)
#define LOG_INFO(format, ...) Log::get_instance()->write_log(1, format, __VA_ARGS__)
#define LOG_WARN(format, ...) Log::get_instance()->write_log(2, format, __VA_ARGS__)
#define LOG_ERROR(format, ...) Log::get_instance()->write_log(3, format, __VA_ARGS__)
#endif
log.cpp
*********************************************************/
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <stdarg.h>
#include "log.h"
#include <pthread.h>
using namespace std;
Log::Log()
{
m_count = 0;
m_mutex = new pthread_mutex_t;
m_cond = new pthread_cond_t;
m_is_async = false;
pthread_mutex_init(m_mutex, NULL);
}
Log::~Log()
{
if(m_fp != NULL)
{
fclose(m_fp);
}
pthread_cond_destroy(m_cond);
if(m_cond != NULL)
{
delete m_cond;
}
pthread_mutex_destroy(m_mutex);
if(m_mutex != NULL)
{
delete m_mutex;
}
}
bool Log::init(const char* file_name, int log_buf_size, int split_lines, int max_queue_size)
{
if(max_queue_size >= 1)
{
m_is_async = true;
// m_log_queue = new block_queue<string>(max_queue_size);
deque<string>(max_queue_size);
pthread_t tid;
pthread_create(&tid, NULL, flush_log_thread, NULL);
}
m_log_buf_size = log_buf_size;
m_buf = new char[m_log_buf_size];
memset(m_buf, '\0', sizeof(m_buf));
m_split_lines = split_lines;
time_t t = time(NULL);
struct tm* sys_tm = localtime(&t);
struct tm my_tm = *sys_tm;
const char *p = strrchr(file_name, '/');
char log_full_name[256] = {0};
if(p == NULL)
{
snprintf(log_full_name, 255, "%d_%02d_%02d_%s",my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday, file_name);
}
else
{
strcpy(log_name, p+1);
strncpy(dir_name, file_name, p - file_name + 1);
snprintf(log_full_name, 255, "%s%d_%02d_%02d_%s",dir_name, my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday, log_name );
}
m_today = my_tm.tm_mday;
m_fp = fopen(log_full_name, "a");
if(m_fp == NULL)
{
return false;
}
return true;
}
void Log::write_log(int level, const char* format, ...)
{
struct timeval now = {0,0};
gettimeofday(&now, NULL);
time_t t = now.tv_sec;
struct tm* sys_tm = localtime(&t);
struct tm my_tm = *sys_tm;
char s[16] = {0};
switch(level)
{
case 0 : strcpy(s, "[debug]:"); break;
case 1 : strcpy(s, "[info]:"); break;
case 2 : strcpy(s, "[warn]:"); break;
case 3 : strcpy(s, "[erro]:"); break;
default:
strcpy(s, "[info]:"); break;
}
pthread_mutex_lock(m_mutex);
m_count++;
if(m_today != my_tm.tm_mday || m_count % m_split_lines == 0) //everyday log
{
char new_log[256] = {0};
fflush(m_fp);
fclose(m_fp);
char tail[16] = {0};
snprintf(tail, 16, "%d_%02d_%02d_", my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday);
if(m_today != my_tm.tm_mday)
{
snprintf(new_log, 255, "%s%s%s", dir_name, tail, log_name);
m_today = my_tm.tm_mday;
m_count = 0;
}
else
{
snprintf(new_log, 255, "%s%s%s.%d", dir_name, tail, log_name, m_count/m_split_lines);
}
m_fp = fopen(new_log, "a");
}
pthread_mutex_unlock(m_mutex);
va_list valst;
va_start(valst, format);
string log_str;
pthread_mutex_lock(m_mutex);
int n = snprintf(m_buf, 48, "%d-%02d-%02d %02d:%02d:%02d.%06d %s ",
my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday,
my_tm.tm_hour, my_tm.tm_min, my_tm.tm_sec, now.tv_usec, s);
int m = vsnprintf(m_buf + n, m_log_buf_size-1, format, valst);
m_buf[n + m - 1] = '\n';
log_str = m_buf;
pthread_mutex_unlock(m_mutex);
if(m_is_async)// && !m_log_queue->full())
{
pthread_mutex_lock(m_mutex);
m_log_queue.push_back(log_str);
pthread_cond_broadcast(m_cond);
pthread_mutex_unlock(m_mutex);
}
else
{
pthread_mutex_lock(m_mutex);
fputs(log_str.c_str(), m_fp);
pthread_mutex_unlock(m_mutex);
}
va_end(valst);
}
void Log::flush(void)
{
pthread_mutex_lock(m_mutex);
fflush(m_fp);
pthread_mutex_unlock(m_mutex);
}
测试文件 main.cpp
#include "log.h"
void *f(void* args)
{
for(int i = 0;i < 10000; i++)
{
Log::get_instance()->write_log(1, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
Log::get_instance()->write_log(2, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
Log::get_instance()->write_log(3, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
LOG_INFO("%d", 123456789);
LOG_ERROR("%d", 123456789);
LOG_DEBUG("%d", 123456789);
LOG_WARN("%d", 123456789);
}
}
int main()
{
Log::get_instance()->init("./mylog.log", 100, 2000000, 10);
//Log::get_instance()->init("./mylog.log", 100, 2000000, 0);//synchronization model
// printf("11111111111111\n");
// sleep(1);
int i = 0;
Log::get_instance()->write_log(1, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
Log::get_instance()->write_log(2, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
Log::get_instance()->write_log(3, "d=%d,c=%c,s=%s,f=%f", i,'a',"log", 1.000);
LOG_INFO("%d", 123456789);
LOG_ERROR("%d", 123456789);
LOG_DEBUG("%d", 123456789);
LOG_WARN("%d", 123456789);
pthread_t id;
for(int i = 0; i < 10; i++)
{
pthread_create(&id, NULL, f, NULL);
pthread_join(id,NULL);
}
//for(;;)
{
sleep(15);
Log::get_instance()->flush();
}
while(1);
// Log::get_instance()->put_log();
return 0;
}
别忘记:makefile
BIN := main
CFLAGS := -g -Wall -lpthread
CC := g++
SRCFILE := $(wildcard *.cpp)
OBJFILE := $(patsubst %.cpp,%.o,$(SRCFILE))
$(BIN): $(OBJFILE)
$(CC) $(CFLAGS) -o $(BIN) $(OBJFILE)
%.o:%.cpp
$(CC) $(CFLAGS) -c $< -o $@
clean :
rm -rf $(OBJFILE) ${BIN}
相关文章推荐
- 精美菜单,自己动手的哦(附图)
- 如何看待自己的专业?
- 自己编程总结点小经验
- jquery网页层拖动实例,保存可以自己实现
- 总结自己应用广度优先搜索(BFS)中的错误(记POJ 1376 Robot结题过程)
- C#教程之自己动手写映射第三节[反射]
- pkill kill 看看自己是谁
- 自己动手写中文分词解析器完整教程,并对出现的问题进行探讨和解决(附完整c#代码和相关dll文件、txt文件下载)
- 自己改编的年会相声台词2015
- 集成activiti-modeler 到 自己的业务系统
- Oracle 自己主动诊断资料档案库 (ADR)、自己主动诊断工作流、ADRCI工具
- VS中如何快捷地给自己的代码添加创建信息注释
- linux自带spi驱动 ,可自己配置CS
- 【云计算的1024种玩法】为求职加分:为自己建个炫酷的简历网页
- 第一次使用theos自己遇到的坑
- 建立自己的3D模型文件
- 将自己做好的数据库导入到服务器中
- 自己搞了个J2ME的俄罗斯方块玩玩
- 自己手动获取MyEclipse 注册码
- 构建自己的Linux 之一 基本框架