自己写的C++日志类log

主要功能是在服务器运行的时候可以打印日志到日志文件中,主要运用到的知识点有线程, 线程锁,条件变量,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  sin gle_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 ) ;
                        sin gle_log = m_log_queue . front ( ) ;
                        fputs ( sin gle_log . c_str ( ) ,  m_fp ) ;
                        m_log_queue . pop_front ( ) ;
                        pthread_mutex_unlock ( m_mutex ) ;
                        }
                   } else {
                        pthread_mutex_lock ( m_mutex ) ;
                        sin gle_log = m_log_queue . front ( ) ;
                        fputs ( sin gle_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  time val  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}

猜你喜欢

转载自blog.csdn.net/u012314708/article/details/52130973