logger.cpp 5.2 KB

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