#ifndef LOG_H
|
#define LOG_H
|
|
#include <stdio.h>
|
#include <iostream>
|
#include <string>
|
#include <stdarg.h>
|
#include <pthread.h>
|
#include "block_queue.h"
|
|
using namespace std;
|
|
class Log
|
{
|
public:
|
// C++11以后,使用局部变量懒汉不用加锁
|
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 close_log, 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;
|
// 从阻塞队列中取出一个日志string,写入文件
|
while (m_log_queue->pop(single_log))
|
{
|
m_mutex.lock();
|
if (check_log_size()) // 检查文件大小
|
{
|
rotate_logs(); // 轮换日志
|
}
|
fputs(single_log.c_str(), m_fp);
|
m_mutex.unlock();
|
}
|
}
|
|
// 检查日志文件大小
|
bool check_log_size()
|
{
|
if (m_fp)
|
{
|
fseek(m_fp, 0, SEEK_END);
|
long file_size = ftell(m_fp);
|
return file_size >= max_size; // 返回文件是否超出限制
|
}
|
return false;
|
}
|
|
// 轮换日志文件
|
void rotate_logs()
|
{
|
fclose(m_fp); // 关闭当前日志文件
|
char new_log[256] = {0};
|
snprintf(new_log, sizeof(new_log), "%s/%s.%lld", dir_name, log_name, m_count / m_split_lines);
|
m_fp = fopen(new_log, "a"); // 打开新的日志文件
|
m_count = 0; // 重置日志计数
|
}
|
|
private:
|
char dir_name[128]; // 路径名
|
char log_name[128]; // log文件名
|
int m_split_lines; // 日志最大行数
|
int m_log_buf_size; // 日志缓冲区大小
|
long long m_count; // 日志行数记录
|
int m_today; // 因为按天分类,记录当前时间是那一天
|
FILE *m_fp; // 打开log的文件指针
|
char *m_buf;
|
block_queue<string> *m_log_queue; // 阻塞队列
|
bool m_is_async; // 是否同步标志位
|
locker m_mutex;
|
int m_close_log; // 关闭日志
|
long max_size = 10 * 1024 * 1024; // 10MB
|
};
|
|
#define LOG_DEBUG(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(0, format, ##__VA_ARGS__); Log::get_instance()->flush();}
|
#define LOG_INFO(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(1, format, ##__VA_ARGS__); Log::get_instance()->flush();}
|
#define LOG_WARN(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(2, format, ##__VA_ARGS__); Log::get_instance()->flush();}
|
#define LOG_ERROR(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(3, format, ##__VA_ARGS__); Log::get_instance()->flush();}
|
|
#endif
|