log.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. #include <unistd.h>
  2. #include <sys/time.h>
  3. #include <time.h>
  4. #include <stdarg.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <string>
  8. #include <thread>
  9. #include <atomic>
  10. #include <vector>
  11. #include <tools.h>
  12. #include <log.h>
  13. #include <log_queue.h>
  14. #include <config_file.h>
  15. struct logp_config
  16. {
  17. int m_show_thread=1;
  18. int m_show_level=1;
  19. int m_show_srcline=1;
  20. int m_print_stdout=0;
  21. int m_level=0;
  22. log_queue*m_queue=nullptr;
  23. std::vector<char*> m_exclude;
  24. std::vector<char> m_exclude_buf;
  25. logp_config()
  26. {
  27. }
  28. logp_config(int level,log_queue*queue)
  29. :m_level(level)
  30. ,m_queue(queue)
  31. {
  32. }
  33. ~logp_config()
  34. {
  35. delete m_queue;
  36. }
  37. int show_level()const{return m_show_level==1;}
  38. int show_srcline()const{return m_show_srcline==1;}
  39. int show_thread()const{return m_show_thread==1;}
  40. int print_stdout()const{return m_print_stdout==1;}
  41. static void trim(char*b,char*e)
  42. {
  43. char*e1=e;
  44. for(;e1>b;--e1)
  45. {
  46. if(!std::isspace(e1[-1]))
  47. break;
  48. }
  49. char*b1=b;
  50. for(;b1<e1;++b1)
  51. {
  52. if(!std::isspace(*b1))
  53. break;
  54. }
  55. memmove(b,b1,e1-b1);
  56. b[e1-b1]=0;
  57. }
  58. void set_exclude(const char*e)
  59. {
  60. if(e==nullptr || *e==0)
  61. return;
  62. m_exclude.clear();
  63. m_exclude_buf.assign(e,e+strlen(e)+1);
  64. char*s=&*m_exclude_buf.begin();
  65. for(;*s;)
  66. {
  67. char*p=strtok_r(s,",",&s);
  68. trim(p,p+strlen(p));
  69. if(strlen(p)==0)
  70. continue;
  71. m_exclude.push_back(p);
  72. }
  73. for(auto p:m_exclude)
  74. {
  75. printf("exclude:%s\n",p);
  76. }
  77. }
  78. bool in_exclude(const char*msg)const
  79. {
  80. for(auto e:m_exclude)
  81. {
  82. if(strstr(msg,e))
  83. return true;
  84. }
  85. return false;
  86. }
  87. };
  88. std::atomic<int> g_log_inited(-2);
  89. std::vector<std::shared_ptr<logp_config>> g_log_queue;
  90. static inline logp_config*get_lc(int index)
  91. {
  92. if(index>=0 && index<(int)g_log_queue.size())
  93. return g_log_queue[index].get();
  94. return nullptr;
  95. }
  96. static inline int level_index(const char*lvls)
  97. {
  98. static const char* lvl[]={"debug","info","warn","error"};
  99. for(size_t i=0;i<sizeof(lvl)/sizeof(char*);i++)
  100. {
  101. if(strcmp(lvls,lvl[i])==0)
  102. return i;
  103. }
  104. return 0;
  105. }
  106. static std::shared_ptr<logp_config> read_config(config_file*f, const char*log_name)
  107. {
  108. const char*fname=f->get(log_name,"fname","");
  109. if(strlen(fname)==0)
  110. return nullptr;
  111. const char* qsize=f->get(log_name,"queue_size","2048");
  112. logp_config lc;
  113. std::unique_ptr<log_queue> log(new log_queue());
  114. char path_buf[4096];
  115. realpath(fname,path_buf);
  116. if(log->open(path_buf, atoi(qsize)<<10))
  117. return nullptr;
  118. const char* level=f->get(log_name,"level","info");
  119. const char* show_level=f->get(log_name,"show_level","1");
  120. const char* show_srcline=f->get(log_name,"show_srcline","1");
  121. const char* show_thread=f->get(log_name,"show_thread","1");
  122. const char* print_stdout=f->get(log_name,"print_stdout","0");
  123. const char* exclude=f->get(log_name,"exclude","");
  124. auto ret=std::make_shared<logp_config>(level_index(level),log.release());
  125. ret->m_show_level=show_level[0]=='1'?1:0;
  126. ret->m_show_thread=show_thread[0]=='1'?1:0;
  127. ret->m_show_srcline=show_srcline[0]=='1'?1:0;
  128. ret->m_print_stdout=print_stdout[0]=='1'?1:0;
  129. ret->set_exclude(exclude);
  130. return ret;
  131. }
  132. int log_impl_init(const char*cfg_name)
  133. {
  134. if(g_log_inited!=-2)
  135. return -1;
  136. ++g_log_inited;
  137. config_file cf;
  138. if(cf.open(cfg_name))
  139. {
  140. --g_log_inited;
  141. return -1;
  142. }
  143. g_log_queue.reserve(10);
  144. auto mlog=read_config(&cf,"main");
  145. if(mlog)
  146. {
  147. g_log_queue.resize(1);
  148. g_log_queue[0]=mlog;
  149. }
  150. char logname[128];
  151. for(int i=1;i<=9;i++)
  152. {
  153. sprintf(logname,"log%d",i);
  154. if(!cf.contains(logname,"fname"))
  155. continue;
  156. auto logn=read_config(&cf,logname);
  157. if(!logn)
  158. continue;
  159. g_log_queue.resize(i+1);
  160. g_log_queue[i]=logn;
  161. }
  162. ++g_log_inited;
  163. return 0;
  164. }
  165. static inline const char*level_str(int level_no)
  166. {
  167. static const char* lvl[]={"debug","info","warn","error"};
  168. if(level_no>=(int)(sizeof(lvl)/sizeof(char*)))
  169. return lvl[0];
  170. return lvl[level_no];
  171. }
  172. static void print_impl(int id,const char*fname,int line,int level,const char*fmt,va_list arg)
  173. {
  174. logp_config*lc=get_lc(id);
  175. if(!lc && id>0)
  176. return;
  177. if(lc && level<lc->m_level)
  178. return;
  179. struct timeval tv;
  180. gettimeofday(&tv,0);
  181. struct tm buff;
  182. const struct tm*t=localtime_r(&tv.tv_sec,&buff);
  183. char *b0=0;
  184. int n=1<<10,c;
  185. do
  186. {
  187. b0=(char*)alloca(c=n+1);
  188. n=snprintf(b0,c,"%d-%02d-%02d %02d:%02d:%02d.%03d " , t->tm_year+1900,t->tm_mon+1,t->tm_mday,
  189. t->tm_hour,t->tm_min,t->tm_sec,(int)(tv.tv_usec/1000));
  190. if((!lc || lc->show_level()) && c>n)
  191. {
  192. n+=snprintf(b0+n,c-n,"[%s]", level_str(level));
  193. }
  194. if(lc && lc->show_thread() && c>n)
  195. {
  196. std::hash<std::thread::id> hasht;
  197. n+=snprintf(b0+n,c-n,"[%04X]", (unsigned)(hasht(std::this_thread::get_id())&0XFFFF));
  198. }
  199. if(lc && lc->show_srcline() && c>n)
  200. {
  201. n+=snprintf(b0+n,c-n,"[%s:%d]", fname,line);
  202. }
  203. if(c>n)
  204. {
  205. n+=snprintf(b0+n,c-n," %s\n", fmt);
  206. }
  207. }while(n>c);
  208. va_list tmp;
  209. va_copy(tmp,arg);
  210. n=4<<10;
  211. char *b1=0;
  212. do
  213. {
  214. if(b1)
  215. {
  216. free(b1);
  217. va_copy(arg,tmp);
  218. }
  219. b1=(char*)malloc(c=n+1);
  220. n=vsnprintf(b1,c,b0,arg);
  221. }while(n>c);
  222. if(!lc)
  223. {
  224. printf("%s",b1);
  225. fflush(stdout);
  226. }
  227. else if(!lc->in_exclude(b1))
  228. {
  229. if(lc->print_stdout())
  230. {
  231. printf("%s",b1);
  232. fflush(stdout);
  233. }
  234. lc->m_queue->put(b1,n);
  235. }
  236. if(b1)free(b1);
  237. }
  238. void log_impl_print_errno(int id,const char*fname,int line,int level,const char*fmt,...)
  239. {
  240. char buff[1024];
  241. int e=errno;
  242. sprintf(buff,"errno=%d,errinfo=%s,addinfo=%s",e,strerror(e),fmt);
  243. va_list ap;
  244. va_start(ap, fmt);
  245. print_impl(id,fname,line,level,buff,ap);
  246. va_end(ap);
  247. }
  248. void log_impl_print (int id,const char*fname,int line,int level,const char*fmt,...)
  249. {
  250. va_list ap;
  251. va_start(ap, fmt);
  252. print_impl(id,fname,line,level,fmt,ap);
  253. va_end(ap);
  254. }
  255. void log_impl_binary(int log_id,const char*fname,int line,const char*addmsg,const char*d,int len)
  256. {
  257. std::string bin=format_bin2(d,len);
  258. log_impl_print(log_id,fname,line,1,"%s,len=%d\n%s",addmsg,len,bin.c_str());
  259. }