log_periodic.c 8.0 KB

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