logger.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <string>
  6. #include <memory>
  7. #include <thread>
  8. #include <log_queue.h>
  9. #include <clock.h>
  10. #include <config_file.h>
  11. #include <sysv_shm.h>
  12. #include <boost/tokenizer.hpp>
  13. #include <boost/utility/string_ref.hpp>
  14. #include <atomic>
  15. #include "log.h"
  16. #include <dirent.h>
  17. #include <string.h>
  18. #include <fnmatch.h>
  19. static void dir_clean(const char*dir,const char*pattern,int count)
  20. {
  21. struct dirent **namelist;
  22. int n = scandir(dir, &namelist, NULL, alphasort);
  23. if (n < 0)
  24. return;
  25. char fname[512];
  26. strcpy(fname,dir);
  27. strcat(fname,"/");
  28. char*p=&fname[strlen(fname)];
  29. for (int i=n-1;i>=0;i--)
  30. {
  31. if(0==fnmatch(pattern,namelist[i]->d_name,0) && count--<=0)
  32. {
  33. strcpy(p,namelist[i]->d_name);
  34. remove(fname);
  35. printf("remove file:%s\n",fname);
  36. }
  37. free(namelist[i]);
  38. }
  39. free(namelist);
  40. }
  41. struct log_file
  42. {
  43. std::string _fname; //文件名模板 /home/zzj/test.log
  44. FILE* _fp;
  45. long _min_size;//文件切割的最大的字节数,当达到这个字节数后,下个对齐时间将切换日志文件
  46. long _cur_size;//当前文件的大小
  47. time_t _last_time;//最后操作文件的时间
  48. int _time_align;//日志文件名对齐的时间,支持 dhm -- 天、小时、分钟
  49. int _file_count;
  50. zclock _err_clock,_check_dir_clock;
  51. log_file(const boost::string_ref&fpath,int file_count=0,int min_size=10,int time_align='h')
  52. :_fname(fpath)
  53. ,_fp(0)
  54. ,_min_size((1LL*min_size)<<20)
  55. ,_cur_size(0)
  56. ,_file_count(file_count)
  57. {
  58. switch(time_align)
  59. {
  60. case 'm': case 'M':
  61. _time_align=60;
  62. break;
  63. case 'd': case 'D':
  64. _time_align=3600*24;
  65. break;
  66. case 'H': case 'h': default:
  67. _time_align=3600;
  68. break;
  69. }
  70. time(&_last_time);
  71. reopen();
  72. }
  73. log_file(const log_file&)=delete;
  74. log_file(log_file&&)=delete;
  75. inline std::string str_time()
  76. {
  77. char buf[128];
  78. time_t tm=time(0);
  79. const struct tm*t=localtime(&tm);
  80. size_t n=
  81. _time_align==3600?sprintf(buf,"_%02d%02d%02d" , t->tm_mon+1,t->tm_mday,t->tm_hour)
  82. : _time_align==60 ?sprintf(buf,"_%02d%02d%02d%02d" , t->tm_mon+1,t->tm_mday, t->tm_hour, t->tm_min)
  83. : sprintf(buf,"_%02d%02d" , t->tm_mon+1,t->tm_mday);
  84. return std::string(buf,n);
  85. }
  86. inline std::string mkname(std::string name)
  87. {
  88. int n=name.find_last_of('.');
  89. name.insert(n,str_time());
  90. return name;
  91. }
  92. void check_file_count()
  93. {
  94. if(!_file_count)
  95. return;
  96. int pos1=_fname.find_last_of('/');
  97. if(pos1==-1)
  98. return;
  99. std::string fn=_fname.substr(pos1+1);
  100. int pos2=fn.find_last_of('.');
  101. if(pos2==-1)
  102. return;
  103. fn.insert(pos2,"_*");
  104. dir_clean(_fname.substr(0,pos1).c_str(),fn.c_str(),_file_count);
  105. }
  106. int reopen()
  107. {
  108. if(_fp) fclose(_fp);
  109. _fp=fopen(_fname.c_str(),"a+");
  110. _cur_size=(uint32_t)ftell(_fp);
  111. _check_dir_clock.reset();
  112. check_file_count();
  113. return 0;
  114. }
  115. void close()
  116. {
  117. if(_fp)
  118. {
  119. fclose(_fp);
  120. _fp=nullptr;
  121. }
  122. }
  123. void put(const char*p,int len)
  124. {
  125. time_t ct=time(0);
  126. if(_cur_size+len>_min_size && _last_time/_time_align != ct/_time_align)
  127. {
  128. close();
  129. rename(_fname.c_str(),mkname(_fname).c_str());
  130. reopen();
  131. }
  132. if(_check_dir_clock.count_ms()>1000)
  133. {
  134. if(access(_fname.c_str(),0)==-1)
  135. reopen();
  136. _check_dir_clock.reset();
  137. }
  138. int rc=fwrite(p,1,len,_fp);
  139. if(rc<len)
  140. {
  141. if(_err_clock.count_ms()>1000)
  142. {
  143. std_errno("fwrite:%s",_fname.c_str());
  144. _err_clock.reset();
  145. }
  146. }
  147. _cur_size+=len;
  148. _last_time=ct;
  149. }
  150. void flush()
  151. {
  152. if(_fp) fflush(_fp);
  153. }
  154. ~log_file()
  155. {
  156. fclose(_fp);
  157. }
  158. };
  159. struct logger
  160. {
  161. std::shared_ptr<log_queue> m_queue;
  162. std::shared_ptr<log_file> m_file;
  163. zclock m_clock;
  164. size_t size_a=0;
  165. logger(std::shared_ptr<log_queue> shm_queue,std::shared_ptr<log_file> log_file)
  166. :m_queue(shm_queue)
  167. ,m_file(log_file)
  168. {
  169. }
  170. void run()
  171. {
  172. size_t size;
  173. char buff[1<<16];
  174. while((size=m_queue->get(buff,sizeof(buff)))>0)
  175. {
  176. m_file->put(buff,size);
  177. size_a+=size;
  178. }
  179. if(m_clock.count_ms()>200 && size_a>0)
  180. {
  181. m_file->flush();
  182. m_clock.reset();
  183. size_a=0;
  184. }
  185. m_queue->keep_alive();
  186. }
  187. ~logger()
  188. {
  189. }
  190. };
  191. static std::shared_ptr<logger> read_config(config_file*f, const char*log_name)
  192. {
  193. const char* fname=f->get(log_name,"fname","");
  194. if(strlen(fname)==0)
  195. return nullptr;
  196. const char* qsize=f->get(log_name,"queue_size","2048");
  197. const char* min_size=f->get(log_name,"min_size","10");
  198. const char* file_count=f->get(log_name,"file_count","0");
  199. const char* time_align=f->get(log_name,"time_align","m");
  200. std::unique_ptr<log_queue> queue(new log_queue());
  201. char path_buf[512];
  202. realpath(fname,path_buf);
  203. if(queue->open(path_buf,atoi(qsize)<<10))
  204. {
  205. std_error("%s:无法打开共享内存。",log_name);
  206. return nullptr;
  207. }
  208. if(!queue->wait_owner())
  209. {
  210. std_error("无法取得%s独占共享内存的权限,logger已经启动?",log_name);
  211. return nullptr;
  212. }
  213. std::unique_ptr<log_file> file(new log_file(fname, atoi(file_count), atoi(min_size),time_align[0]));
  214. std_info("初始化日志%s成功:{文件名=%s, 输出队列大小=%dkB, 最小切换大小=%dMB, 切换对齐时间=%c}",
  215. log_name,fname,atoi(qsize),atoi(min_size),time_align[0]);
  216. return std::shared_ptr<logger>(new logger(std::move(queue),std::move(file)));
  217. }
  218. std::atomic<int> g_quit_event(0);
  219. int main(int argc,char*argv[])
  220. {
  221. const char*cfg_file="../etc/log.ini";
  222. for(int i=1;i<argc;i++)
  223. {
  224. if(strncmp(argv[i],"-f",2)==0)
  225. {
  226. cfg_file=&argv[i][2];
  227. }
  228. }
  229. std::vector<std::shared_ptr<logger>> logs;
  230. config_file config;
  231. std_info("初始化配置文件:%s",cfg_file);
  232. if(config.open(cfg_file))
  233. {
  234. std_error("读配置文件%s失败",cfg_file);
  235. return -1;
  236. }
  237. std_info("读取配置文件:%s成功",cfg_file);
  238. std::shared_ptr<logger> logm=read_config(&config,"main");
  239. if(!logm)
  240. {
  241. std_error("无法成功初始化main.log,请检查日志配置文件:%s,日志程序将退出。",cfg_file);
  242. return -1;
  243. }
  244. logs.push_back(logm);
  245. std_info("初始化主日志main.log成功");
  246. std_info("开始初始化log1-log9,目前系统最多支持9个子日志。");
  247. char logname[128];
  248. for(int i=1;i<10;i++)
  249. {
  250. sprintf(logname,"log%d",i);
  251. if(!config.contains(logname,"fname"))
  252. continue;
  253. auto logn=read_config(&config,logname);
  254. if(!logn)
  255. continue;
  256. logs.push_back(logn);
  257. }
  258. for(int i=0;;i++)
  259. {
  260. std::for_each(logs.begin(),logs.end(),[](std::shared_ptr<logger>&log){
  261. log->run();
  262. });
  263. usleep(10000);
  264. }
  265. return 0;
  266. }