123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <string>
- #include <memory>
- #include <thread>
- #include <log_queue.h>
- #include <clock.h>
- #include <config_file.h>
- #include <sysv_shm.h>
- #include <boost/tokenizer.hpp>
- #include <boost/utility/string_ref.hpp>
- #include <atomic>
- #include "log.h"
- #include <dirent.h>
- #include <string.h>
- #include <fnmatch.h>
- static void dir_clean(const char*dir,const char*pattern,int count)
- {
- struct dirent **namelist;
- int n = scandir(dir, &namelist, NULL, alphasort);
- if (n < 0)
- return;
- char fname[512];
- strcpy(fname,dir);
- strcat(fname,"/");
- char*p=&fname[strlen(fname)];
- for (int i=n-1;i>=0;i--)
- {
- if(0==fnmatch(pattern,namelist[i]->d_name,0) && count--<=0)
- {
- strcpy(p,namelist[i]->d_name);
- remove(fname);
- printf("remove file:%s\n",fname);
- }
- free(namelist[i]);
- }
- free(namelist);
- }
- struct log_file
- {
- std::string _fname; //文件名模板 /home/zzj/test.log
- FILE* _fp;
- long _min_size;//文件切割的最大的字节数,当达到这个字节数后,下个对齐时间将切换日志文件
- long _cur_size;//当前文件的大小
- time_t _last_time;//最后操作文件的时间
- int _time_align;//日志文件名对齐的时间,支持 dhm -- 天、小时、分钟
- int _file_count;
- zclock _err_clock,_check_dir_clock;
- log_file(const boost::string_ref&fpath,int file_count=0,int min_size=10,int time_align='h')
- :_fname(fpath)
- ,_fp(0)
- ,_min_size((1LL*min_size)<<20)
- ,_cur_size(0)
- ,_file_count(file_count)
- {
- switch(time_align)
- {
- case 'm': case 'M':
- _time_align=60;
- break;
- case 'd': case 'D':
- _time_align=3600*24;
- break;
- case 'H': case 'h': default:
- _time_align=3600;
- break;
- }
- time(&_last_time);
- reopen();
- }
- log_file(const log_file&)=delete;
- log_file(log_file&&)=delete;
- inline std::string str_time()
- {
- char buf[128];
- time_t tm=time(0);
- const struct tm*t=localtime(&tm);
- size_t n=
- _time_align==3600?sprintf(buf,"_%02d%02d%02d" , t->tm_mon+1,t->tm_mday,t->tm_hour)
- : _time_align==60 ?sprintf(buf,"_%02d%02d%02d%02d" , t->tm_mon+1,t->tm_mday, t->tm_hour, t->tm_min)
- : sprintf(buf,"_%02d%02d" , t->tm_mon+1,t->tm_mday);
- return std::string(buf,n);
- }
- inline std::string mkname(std::string name)
- {
- int n=name.find_last_of('.');
- name.insert(n,str_time());
- return name;
- }
- void check_file_count()
- {
- if(!_file_count)
- return;
- int pos1=_fname.find_last_of('/');
- if(pos1==-1)
- return;
- std::string fn=_fname.substr(pos1+1);
- int pos2=fn.find_last_of('.');
- if(pos2==-1)
- return;
- fn.insert(pos2,"_*");
- dir_clean(_fname.substr(0,pos1).c_str(),fn.c_str(),_file_count);
- }
- int reopen()
- {
- if(_fp) fclose(_fp);
- _fp=fopen(_fname.c_str(),"a+");
- _cur_size=(uint32_t)ftell(_fp);
- _check_dir_clock.reset();
- check_file_count();
- return 0;
- }
- void close()
- {
- if(_fp)
- {
- fclose(_fp);
- _fp=nullptr;
- }
-
- }
- void put(const char*p,int len)
- {
- time_t ct=time(0);
- if(_cur_size+len>_min_size && _last_time/_time_align != ct/_time_align)
- {
- close();
- rename(_fname.c_str(),mkname(_fname).c_str());
- reopen();
- }
- if(_check_dir_clock.count_ms()>1000)
- {
- if(access(_fname.c_str(),0)==-1)
- reopen();
- _check_dir_clock.reset();
- }
- int rc=fwrite(p,1,len,_fp);
- if(rc<len)
- {
- if(_err_clock.count_ms()>1000)
- {
- std_errno("fwrite:%s",_fname.c_str());
- _err_clock.reset();
- }
- }
- _cur_size+=len;
- _last_time=ct;
- }
- void flush()
- {
- if(_fp) fflush(_fp);
- }
- ~log_file()
- {
- fclose(_fp);
- }
- };
- struct logger
- {
- std::shared_ptr<log_queue> m_queue;
- std::shared_ptr<log_file> m_file;
- zclock m_clock;
- size_t size_a=0;
- logger(std::shared_ptr<log_queue> shm_queue,std::shared_ptr<log_file> log_file)
- :m_queue(shm_queue)
- ,m_file(log_file)
- {
- }
- void run()
- {
- size_t size;
- char buff[1<<16];
- while((size=m_queue->get(buff,sizeof(buff)))>0)
- {
- m_file->put(buff,size);
- size_a+=size;
- }
- if(m_clock.count_ms()>200 && size_a>0)
- {
- m_file->flush();
- m_clock.reset();
- size_a=0;
- }
- m_queue->keep_alive();
- }
- ~logger()
- {
- }
- };
- static std::shared_ptr<logger> read_config(config_file*f, const char*log_name)
- {
- const char* fname=f->get(log_name,"fname","");
- if(strlen(fname)==0)
- return nullptr;
- const char* qsize=f->get(log_name,"queue_size","2048");
- const char* min_size=f->get(log_name,"min_size","10");
- const char* file_count=f->get(log_name,"file_count","0");
- const char* time_align=f->get(log_name,"time_align","m");
- std::unique_ptr<log_queue> queue(new log_queue());
- char path_buf[512];
- realpath(fname,path_buf);
- if(queue->open(path_buf,atoi(qsize)<<10))
- {
- std_error("%s:无法打开共享内存。",log_name);
- return nullptr;
- }
-
- if(!queue->wait_owner())
- {
- std_error("无法取得%s独占共享内存的权限,logger已经启动?",log_name);
- return nullptr;
- }
-
- std::unique_ptr<log_file> file(new log_file(fname, atoi(file_count), atoi(min_size),time_align[0]));
- std_info("初始化日志%s成功:{文件名=%s, 输出队列大小=%dkB, 最小切换大小=%dMB, 切换对齐时间=%c}",
- log_name,fname,atoi(qsize),atoi(min_size),time_align[0]);
- return std::shared_ptr<logger>(new logger(std::move(queue),std::move(file)));
- }
- std::atomic<int> g_quit_event(0);
- int main(int argc,char*argv[])
- {
- const char*cfg_file="../etc/log.ini";
- for(int i=1;i<argc;i++)
- {
- if(strncmp(argv[i],"-f",2)==0)
- {
- cfg_file=&argv[i][2];
- }
- }
- std::vector<std::shared_ptr<logger>> logs;
- config_file config;
- std_info("初始化配置文件:%s",cfg_file);
- if(config.open(cfg_file))
- {
- std_error("读配置文件%s失败",cfg_file);
- return -1;
- }
- std_info("读取配置文件:%s成功",cfg_file);
-
- std::shared_ptr<logger> logm=read_config(&config,"main");
- if(!logm)
- {
- std_error("无法成功初始化main.log,请检查日志配置文件:%s,日志程序将退出。",cfg_file);
- return -1;
- }
- logs.push_back(logm);
- std_info("初始化主日志main.log成功");
-
- std_info("开始初始化log1-log9,目前系统最多支持9个子日志。");
- char logname[128];
- for(int i=1;i<10;i++)
- {
- sprintf(logname,"log%d",i);
- if(!config.contains(logname,"fname"))
- continue;
- auto logn=read_config(&config,logname);
- if(!logn)
- continue;
- logs.push_back(logn);
- }
- for(int i=0;;i++)
- {
- std::for_each(logs.begin(),logs.end(),[](std::shared_ptr<logger>&log){
- log->run();
- });
- usleep(10000);
- }
- return 0;
- }
|