log_periodic.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. #include "precompile.h"
  2. #include <stdio.h>
  3. #include "log_periodic.h"
  4. #include "log_base.h"
  5. #include "log_factory.h"
  6. #include "log.h"
  7. #include "spinlock.h"
  8. #include "fileutil.h"
  9. #include <winpr/string.h>
  10. #include <winpr/wlog.h>
  11. #define TAG TOOLKIT_TAG("log_periodic")
  12. typedef struct periodiclogfactory_t periodiclogfactory_t;
  13. extern int fastlock_tryenter(lock_t l);
  14. typedef struct periodicfile_t {
  15. logbase_t base;
  16. char curr_file[MAX_PATH];
  17. char path_template[MAX_PATH];
  18. FILE *fp;
  19. LONG use_lock;
  20. lock_t lock;
  21. LONG flush;
  22. int first_record;
  23. }periodicfile_t;
  24. struct periodiclogfactory_t
  25. {
  26. logfactory_t base;
  27. };
  28. static char* ExpandTemplatePath(SYSTEMTIME *pTime, const char *pTemplatePath, char *path)
  29. {
  30. char *q = path;
  31. const char *p = pTemplatePath;
  32. while (*p != 0) {
  33. if (*p == '{') {
  34. if (0 == strncmp(p, "{yyyy}", 6)) {
  35. int t = sprintf(q, "%04d", pTime->wYear);
  36. p+=6;
  37. q+=t;
  38. continue;
  39. } else if (0 == strncmp(p, "{MM}", 4)) {
  40. int t = sprintf(q, "%02d", pTime->wMonth);
  41. p+=4;
  42. q+=t;
  43. continue;
  44. } else if (0 == strncmp(p, "{dd}", 4)) {
  45. int t = sprintf(q, "%02d", pTime->wDay);
  46. p+=4;
  47. q+=t;
  48. continue;
  49. } else if (0 == strncmp(p, "{hh}", 4)) {
  50. int t = sprintf(q, "%02d", pTime->wHour);
  51. p+=4;
  52. q+=t;
  53. continue;
  54. } else if (0 == strncmp(p, "{mm}", 4)) {
  55. int t = sprintf(q, "%02d", pTime->wMinute);
  56. p+=4;
  57. q+=t;
  58. continue;
  59. } else if (0 == strncmp(p, "{ss}", 4)) {
  60. int t = sprintf(q, "%02d", pTime->wSecond);
  61. p+=4;
  62. q+=t;
  63. continue;
  64. }
  65. }
  66. *q++ = *p++;
  67. }
  68. *q = 0;
  69. return path;
  70. }
  71. static void periodicfilefactory_destroy(void *self)
  72. {
  73. periodiclogfactory_t *fac = (periodiclogfactory_t *)self;
  74. if (fac) {
  75. free(fac->base.name);
  76. free(fac);
  77. }
  78. }
  79. static void* periodicfilefactory_create_log(void *self, const char* inst)
  80. {
  81. periodiclogfactory_t *fac = (periodiclogfactory_t *)self;
  82. periodicfile_t *log = MALLOC_T(periodicfile_t);
  83. log->base.level = XLOG_LEVEL_ALL;
  84. log->base.factory = self;
  85. log->base.inst_name = _strdup(inst);
  86. log->fp = NULL;
  87. log->use_lock = 0;
  88. log->flush = 1;
  89. log->curr_file[0] = 0;
  90. log->path_template[0] = 0;
  91. log->first_record = 0;
  92. fastlock_init(log->lock);
  93. return log;
  94. }
  95. static int periodicfilefactory_set_log_param(void *self, void *log, const char *key, const char *value)
  96. {
  97. periodiclogfactory_t *fac = (periodiclogfactory_t *)self;
  98. periodicfile_t *plog = (periodicfile_t *)log;
  99. if (_stricmp(key, "file") == 0) {
  100. if (value != NULL) {
  101. #ifdef _WIN32
  102. if (strchr(value, ':') == NULL) {
  103. #else
  104. if (value[0] != '/') {
  105. #endif // _WIN32
  106. char* p;
  107. GetModuleFileNameA(NULL, plog->path_template, MAX_PATH);
  108. p = strrchr(plog->path_template, '/');
  109. if (!p)
  110. p = strrchr(plog->path_template, '\\');
  111. *(p + 1) = 0;
  112. strcpy(p + 1, value);
  113. }
  114. else {
  115. strcpy(plog->path_template, value);
  116. }
  117. }
  118. else {
  119. return -1;
  120. }
  121. } else if (_stricmp(key, "use_lock") == 0) {
  122. if (_stricmp(value, "true") == 0 || _stricmp(value, "1") == 0) {
  123. plog->use_lock = 1;
  124. } else {
  125. plog->use_lock = 0;
  126. }
  127. }else if (_stricmp(key, "flush") == 0) {
  128. if (_stricmp(value, "true") == 0 || _stricmp(value, "1") == 0) {
  129. plog->flush = 1;
  130. } else {
  131. plog->flush = 0;
  132. }
  133. } else if (_stricmp(key, "level") == 0) {
  134. if (_stricmp(value, "all") == 0) {
  135. plog->base.level = 0;
  136. } else if (_stricmp(value, "trace") == 0) {
  137. plog->base.level = 1;
  138. } else if (_stricmp(value, "debug") == 0) {
  139. plog->base.level = 2;
  140. } else if (_stricmp(value, "info") == 0) {
  141. plog->base.level = 3;
  142. } else if (_stricmp(value, "warn") == 0) {
  143. plog->base.level = 4;
  144. } else if (_stricmp(value, "error") == 0) {
  145. plog->base.level = 5;
  146. } else if (_stricmp(value, "fatal") == 0) {
  147. plog->base.level = 6;
  148. } else if (_stricmp(value, "none") == 0) {
  149. plog->base.level = 7;
  150. } else {
  151. return -1;
  152. }
  153. } else {
  154. return -1;
  155. }
  156. return 0;
  157. }
  158. static int periodicfilefactory_init_log(void *self, void *log)
  159. {
  160. periodiclogfactory_t *fac = (periodiclogfactory_t *)self;
  161. periodicfile_t *plog = (periodicfile_t *)log;
  162. return 0;
  163. }
  164. static int periodicfilefactory_term_log(void *self, void *log)
  165. {
  166. periodiclogfactory_t *fac = (periodiclogfactory_t *)self;
  167. periodicfile_t *plog = (periodicfile_t *)log;
  168. if (plog->fp) {
  169. fclose(plog->fp);
  170. plog->fp = NULL;
  171. }
  172. plog->use_lock = 0;
  173. return 0;
  174. }
  175. static void periodicfilefactory_destroy_log(void *self, void *log)
  176. {
  177. periodiclogfactory_t *fac = (periodiclogfactory_t *)self;
  178. periodicfile_t *plog = (periodicfile_t *)log;
  179. if (plog) {
  180. if (plog->base.inst_name)
  181. free(plog->base.inst_name);
  182. free(plog);
  183. }
  184. }
  185. static int periodicfilefactory_record_log(void *self,
  186. void *log,
  187. int level,
  188. unsigned long ts_low,
  189. unsigned long ts_high,
  190. const char *s,
  191. int sn)
  192. {
  193. periodiclogfactory_t *fac = (periodiclogfactory_t *)self;
  194. periodicfile_t *plog = (periodicfile_t *)log;
  195. SYSTEMTIME st;
  196. FILETIME utc_ft, local_ft;
  197. char tmp[MAX_PATH];
  198. char *ptmp;
  199. int status = 0;
  200. //存在可能,某个线程正在Dbg, 未释放,但线程被destory导致lock未释放
  201. if (plog->use_lock) {
  202. if (*(plog->lock) == 1)
  203. {
  204. int i = 0;
  205. for (i = 0; i < 10 && 0 == fastlock_tryenter(plog->lock); i++) {
  206. }
  207. if(10 == i)
  208. fastlock_leave(plog->lock);
  209. }
  210. else
  211. fastlock_enter(plog->lock);
  212. }
  213. //TODO: test the calculate performation.
  214. #ifdef _WIN32
  215. utc_ft.dwLowDateTime = (DWORD)ts_low;
  216. utc_ft.dwHighDateTime = (DWORD)ts_high;
  217. FileTimeToLocalFileTime(&utc_ft, &local_ft);
  218. FileTimeToSystemTime(&local_ft, &st);
  219. #else
  220. GetLocalTime(&st);
  221. #endif // _WIN32
  222. ExpandTemplatePath(&st, plog->path_template, tmp);
  223. ptmp = strrchr(tmp, '/');
  224. if(!ptmp)
  225. ptmp = strrchr(tmp, '\\');
  226. *ptmp = 0;
  227. CreateDirRecursiveA(tmp);
  228. *ptmp = SPLIT_SLASH;
  229. if (strcmp(tmp, plog->curr_file) != 0) {
  230. if (plog->fp) {
  231. fclose(plog->fp);
  232. plog->fp = NULL;
  233. }
  234. plog->fp = fopen(tmp, "ab");
  235. if (plog->fp) {
  236. /*fix bug*/
  237. int flen = 0;
  238. strcpy(plog->curr_file, tmp);
  239. fseek(plog->fp, 0, SEEK_END);
  240. flen = ftell(plog->fp);
  241. plog->first_record = !flen;
  242. } else {
  243. plog->curr_file[0] = 0;
  244. }
  245. }
  246. if (plog->fp) {
  247. DWORD dwBytesWritten = 0;
  248. char tmp[64];
  249. int n;
  250. if (plog->first_record) {
  251. n = sprintf(tmp, "[%02d:%02d:%02d.%03d][%s] ",
  252. st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, log_level2str(level));
  253. plog->first_record = 0;
  254. } else {
  255. n = sprintf(tmp, LINE_BREAK_STR "[%02d:%02d:%02d.%03d][%5u][%s] ",
  256. st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, GetCurrentThreadId(), log_level2str(level));
  257. }
  258. _fwrite_nolock(tmp, n, 1, plog->fp);
  259. _fwrite_nolock(s, sn, 1, plog->fp);
  260. // Only for debugging. [3/24/2020 16:58 Gifur]
  261. WLog_DBG(TAG, s);
  262. if (plog->flush)
  263. _fflush_nolock(plog->fp);
  264. } else {
  265. status = -1;
  266. }
  267. if (plog->use_lock) {
  268. fastlock_leave(plog->lock);
  269. }
  270. return status;
  271. }
  272. int periodicfilefactory_create(logfactory_t **p_fac)
  273. {
  274. periodiclogfactory_t *fac;
  275. if (!p_fac)
  276. return -1;
  277. fac = ZALLOC_T(periodiclogfactory_t);
  278. if (!fac) {
  279. return -1;
  280. }
  281. fac->base.name = _strdup("periodic");
  282. fac->base.record_log = &periodicfilefactory_record_log;
  283. fac->base.init_log = &periodicfilefactory_init_log;
  284. fac->base.set_log_param = &periodicfilefactory_set_log_param;
  285. fac->base.term_log = &periodicfilefactory_term_log;
  286. fac->base.create_log = &periodicfilefactory_create_log;
  287. fac->base.destroy_log = &periodicfilefactory_destroy_log;
  288. fac->base.destroy = &periodicfilefactory_destroy;
  289. *p_fac = &fac->base;
  290. return 0;
  291. }