hlog.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #include "hlog.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdarg.h>
  5. #include "htime.h" // for get_datetime
  6. static char s_logfile[256] = DEFAULT_LOG_FILE;
  7. static int s_loglevel = DEFAULT_LOG_LEVEL;
  8. static bool s_logcolor = false;
  9. static bool s_fflush = true;
  10. static int s_remain_days = DEFAULT_LOG_REMAIN_DAYS;
  11. static char s_logbuf[LOG_BUFSIZE];
  12. // for thread-safe
  13. #include "hmutex.h"
  14. #ifdef OS_WIN
  15. static hmutex_t s_mutex;
  16. static honce_t s_once = HONCE_INIT;
  17. static void WINAPI __mutex_init() {
  18. hmutex_init(&s_mutex);
  19. }
  20. #define HLOG_LOCK\
  21. honce(&s_once, __mutex_init);\
  22. hmutex_lock(&s_mutex);
  23. #else
  24. static hmutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;
  25. #define HLOG_LOCK hmutex_lock(&s_mutex);
  26. #endif
  27. #define HLOG_UNLOCK hmutex_unlock(&s_mutex);
  28. static void ts_logfile(time_t ts, char* buf, int len) {
  29. struct tm* tm = localtime(&ts);
  30. snprintf(buf, len, "%s-%04d-%02d-%02d.log",
  31. s_logfile,
  32. tm->tm_year+1900,
  33. tm->tm_mon+1,
  34. tm->tm_mday);
  35. }
  36. static FILE* shift_logfile() {
  37. static FILE* s_logfp = NULL;
  38. static char s_cur_logfile[256] = {0};
  39. static time_t s_last_logfile_ts = 0;
  40. time_t ts_now = time(NULL);
  41. int interval_days = s_last_logfile_ts == 0 ? 0 : (ts_now / SECONDS_PER_DAY - s_last_logfile_ts / SECONDS_PER_DAY);;
  42. if (s_logfp == NULL || interval_days > 0) {
  43. // close old logfile
  44. if (s_logfp) {
  45. fclose(s_logfp);
  46. s_logfp = NULL;
  47. }
  48. else {
  49. interval_days = 30;
  50. }
  51. if (interval_days >= s_remain_days) {
  52. // remove [today-interval_days, today-s_remain_days] logfile
  53. char rm_logfile[256] = {0};
  54. for (int i = interval_days; i >= s_remain_days; --i) {
  55. time_t ts_rm = ts_now - i * SECONDS_PER_DAY;
  56. ts_logfile(ts_rm, rm_logfile, sizeof(rm_logfile));
  57. remove(rm_logfile);
  58. }
  59. }
  60. else {
  61. // remove today-s_remain_days logfile
  62. char rm_logfile[256] = {0};
  63. time_t ts_rm = ts_now - s_remain_days * SECONDS_PER_DAY;
  64. ts_logfile(ts_rm, rm_logfile, sizeof(rm_logfile));
  65. remove(rm_logfile);
  66. }
  67. }
  68. // open today logfile
  69. if (s_logfp == NULL) {
  70. ts_logfile(ts_now, s_cur_logfile, sizeof(s_cur_logfile));
  71. s_logfp = fopen(s_cur_logfile, "a"); // note: append-mode for multi-processes
  72. s_last_logfile_ts = ts_now;
  73. }
  74. // rewrite if too big
  75. if (s_logfp && ftell(s_logfp) > MAX_LOG_FILESIZE) {
  76. fclose(s_logfp);
  77. s_logfp = NULL;
  78. s_logfp = fopen(s_cur_logfile, "w");
  79. }
  80. return s_logfp;
  81. }
  82. int hlog_set_file(const char* logfile) {
  83. if (logfile == NULL || strlen(logfile) == 0) return -10;
  84. strncpy(s_logfile, logfile, sizeof(s_logfile));
  85. // remove suffix .log
  86. char* suffix = strrchr(s_logfile, '.');
  87. if (suffix && strcmp(suffix, ".log") == 0) {
  88. *suffix = '\0';
  89. }
  90. return 0;
  91. }
  92. void hlog_set_level(int level) {
  93. s_loglevel = level;
  94. }
  95. void hlog_set_remain_days(int days) {
  96. s_remain_days = days;
  97. }
  98. void hlog_enable_color(int on) {
  99. s_logcolor = on;
  100. }
  101. int hlog_printf(int level, const char* fmt, ...) {
  102. if (level < s_loglevel)
  103. return -10;
  104. const char* pcolor = "";
  105. const char* plevel = "";
  106. #define CASE_LOG(id, str, clr) \
  107. case id: plevel = str; pcolor = clr; break;
  108. switch (level) {
  109. FOREACH_LOG(CASE_LOG)
  110. }
  111. #undef CASE_LOG
  112. HLOG_LOCK
  113. FILE* fp = shift_logfile();
  114. if (fp == NULL) {
  115. HLOG_UNLOCK
  116. return -20;
  117. }
  118. datetime_t now = datetime_now();
  119. int len = snprintf(s_logbuf, LOG_BUFSIZE, "[%04d-%02d-%02d %02d:%02d:%02d.%03d][%s]: ",
  120. now.year, now.month, now.day, now.hour, now.min, now.sec, now.ms, plevel);
  121. va_list ap;
  122. va_start(ap, fmt);
  123. len += vsnprintf(s_logbuf + len, LOG_BUFSIZE-len, fmt, ap);
  124. va_end(ap);
  125. if (s_logcolor) {
  126. fprintf(fp, "%s%s%s\n", pcolor, s_logbuf, CL_CLR);
  127. }
  128. else {
  129. fprintf(fp, "%s\n", s_logbuf);
  130. }
  131. if (s_fflush) {
  132. fflush(fp);
  133. }
  134. HLOG_UNLOCK
  135. return len;
  136. }
  137. void hlog_set_fflush(int on) {
  138. s_fflush = on;
  139. }
  140. void hlog_fflush() {
  141. HLOG_LOCK
  142. FILE* fp = shift_logfile();
  143. if (fp) {
  144. fflush(fp);
  145. }
  146. HLOG_UNLOCK
  147. }