linux c/c++ 后台开发常用组件之:c++日志模块
2013-05-17 11:28
309 查看
日志是服务端开发必不可少的模块,工作过几个公司,基本每个公司或者项目组都有自己的日志模块,有使用开源的,也有自己写的,这是自己写的一个日志模块,经过线上大并发的测试,性能良好,使用也较方便。该日志采用的是单例模式,支持自动按天分文件,按日志行数自动分文件,是多线程安全的单例模式,没有外部依赖,linux操作系统均可以使用。在日志安全级别高的情况,不能丢失日志的情况,可以使用同步模式, 在要求应用程序性能高对日志安全级别不高的情况可以使用异步模式,异步模式就是在程序异常奔溃或者是重启服务的情况可能有日志丢失。
/******************************************** function: thread safe blocking queue. author: liuyi date: 2014.11.13 version: 2.0 ********************************************/ #ifndef BLOCK_QUEUE_H #define BLOCK_QUEUE_H #include <iostream> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> using namespace std; template<class T> class block_queue { public: block_queue(int max_size = 1000) { if(max_size <= 0) { exit(-1); } m_max_size = max_size; m_array = new T[max_size]; m_size = 0; m_front = -1; m_back = -1; m_mutex = new pthread_mutex_t; m_cond = new pthread_cond_t; pthread_mutex_init(m_mutex, NULL); pthread_cond_init(m_cond, NULL); } void clear() { pthread_mutex_lock(m_mutex); m_size = 0; m_front = -1; m_back = -1; pthread_mutex_unlock(m_mutex); } ~block_queue() { pthread_mutex_lock(m_mutex); if(m_array != NULL) delete m_array; pthread_mutex_unlock(m_mutex); pthread_mutex_destroy(m_mutex); pthread_cond_destroy(m_cond); delete m_mutex; delete m_cond; } bool full()const { pthread_mutex_lock(m_mutex); if(m_size >= m_max_size) { pthread_mutex_unlock(m_mutex); return true; } pthread_mutex_unlock(m_mutex); return false; } bool empty()const { pthread_mutex_lock(m_mutex); if(0 == m_size) { pthread_mutex_unlock(m_mutex); return true; } pthread_mutex_unlock(m_mutex); return false; } bool front(T& value)const { pthread_mutex_lock(m_mutex); if(0 == m_size) { pthread_mutex_unlock(m_mutex); return false; } value = m_array[m_front]; pthread_mutex_unlock(m_mutex); return true; } bool back(T& value)const { pthread_mutex_lock(m_mutex); if(0 == m_size) { pthread_mutex_unlock(m_mutex); return false; } value = m_array[m_back]; pthread_mutex_unlock(m_mutex); return true; } int size()const { int tmp = 0; pthread_mutex_lock(m_mutex); tmp = m_size; pthread_mutex_unlock(m_mutex); return tmp; } int max_size()const { int tmp = 0; pthread_mutex_lock(m_mutex); tmp = m_max_size; pthread_mutex_unlock(m_mutex); return tmp; } bool push(const T& item) { pthread_mutex_lock(m_mutex); if(m_size >= m_max_size) { pthread_cond_broadcast(m_cond); pthread_mutex_unlock(m_mutex); return false; } m_back = (m_back + 1) % m_max_size; m_array[m_back] = item; m_size++; pthread_cond_broadcast(m_cond); pthread_mutex_unlock(m_mutex); return true; } bool pop(T& item) { pthread_mutex_lock(m_mutex); while(m_size <= 0) { if(0 != pthread_cond_wait(m_cond, m_mutex)) { pthread_mutex_unlock(m_mutex); return false; } } m_front = (m_front + 1) % m_max_size; item = m_array[m_front]; m_size--; pthread_mutex_unlock(m_mutex); return true; } bool pop(T& item, int ms_timeout) { struct timespec t = {0,0}; struct timeval now = {0,0}; gettimeofday(&now, NULL); pthread_mutex_lock(m_mutex); if(m_size <= 0) { t.tv_sec = now.tv_sec + ms_timeout/1000; t.tv_nsec = (ms_timeout % 1000)*1000; if(0 != pthread_cond_timedwait(m_cond, m_mutex, &t)) { pthread_mutex_unlock(m_mutex); return false; } } if(m_size <= 0) { pthread_mutex_unlock(m_mutex); return false; } m_front = (m_front + 1) % m_max_size; item = m_array[m_front];m_size--; pthread_mutex_unlock(m_mutex); return true; } private: pthread_mutex_t *m_mutex; pthread_cond_t *m_cond; T *m_array; int m_size; int m_max_size; int m_front; int m_back; }; #endif
/******************************************************** function:log class version:1.0 date:2013.4.19 modify:2014.12.21 *********************************************************/ #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: 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(m_log_queue->pop(single_log)) { pthread_mutex_lock(m_mutex); fputs(single_log.c_str(), m_fp); pthread_mutex_unlock(m_mutex); } } private: pthread_mutex_t *m_mutex; 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; block_queue<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
/******************************************************** function:log class version:1.0 date:2013.4.19 modify:2014.12.21 *********************************************************/ #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_is_async = false; pthread_mutex_init(m_mutex, NULL); } Log::~Log() { if(m_fp != NULL) { fclose(m_fp); } 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); 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()) { m_log_queue->push(log_str); } 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); }
#include "log.h" void *f(void* args) { for(int i = 0;i < 100; 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 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 < 1; i++) { pthread_create(&id, NULL, f, NULL); pthread_join(id,NULL); } //for(;;) { sleep(15); Log::get_instance()->flush(); } return 0; }
相关文章推荐
- linux c/c++ 后台开发常用组件之:c++日志模块
- c/c++ 后台开发常用组件之:c++日志模块
- linux c/c++ 后台开发常用组件之:高级字符串处理库
- linux c/c++ 后台开发基础之:c++日志模块
- linux c/c++ 后台开发常用组件之:高性能阻塞队列
- linux c/c++ 后台开发常用组件之: 高性能LRU本地缓存
- linux c/c++后台开发组件之:memcached 单机和分布式集群c++客户端
- linux c/c++ 后台开发常用算法之:一致性哈希算法
- linux c/c++ 后台开发常用算法之:md5算法c++版实现
- linux C/C++服务器后台开发面试题总结
- Linux平台下基于BitTorrent应用层协议的下载软件开发--日志管理模块(log.h)
- Linux 后台开发工作中常用的开源库
- linux下C++开发常用工具
- ThinkPHP 3.2.3 简单后台模块开发(一)常用配置
- linux后台开发常用调试工具
- Linux 后台开发常用命令
- linux后台开发排错常用工具
- Linux下C++开发常用命令
- linux C/C++服务器后台开发面试题总结
- ThinkPHP 3.2.3 简单后台模块开发(一)常用配置