log.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * 文件名: log.c
  3. * 目标: 日志系统对aFun的API
  4. * 注意: 因为tool模块需要使用log系统, 因此log系统尽量少点依赖tool模块, 避免造成死循环
  5. * 仅依赖:
  6. * time_s.h 中 getTime -> strCopy
  7. * mem.h 中 free
  8. * file.h 中 getFileSize
  9. * stdio_.h
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <stdarg.h>
  14. #include <string.h>
  15. #include "macro.h"
  16. #include "mem.h"
  17. #include "log.h"
  18. #include "time_s.h"
  19. #include "file.h"
  20. #include "stdio_.h"
  21. #ifdef aFunWIN32
  22. #include <windows.h>
  23. #define getpid() (long)GetCurrentProcessId()
  24. #define gettid() (long)GetCurrentThreadId()
  25. // cygwin没有syscall.h, 因此需要依赖 windows 的 api
  26. #else
  27. #include <unistd.h>
  28. #include "sys/syscall.h"
  29. #define gettid() (long)syscall(SYS_gettid)
  30. #define getpid() (long)getpid()
  31. #endif
  32. #undef calloc
  33. static struct LogFactory {
  34. bool init; // 是否已经初始化
  35. long pid;
  36. FILE *log; // 记录文件输出的位置
  37. FILE *csv;
  38. LogFactoryPrintConsole print_console; // 输出到终端、
  39. Logger sys_log;
  40. } log_factory = {.init=false};
  41. static void destructLogSystem_at_exit(void);
  42. /*
  43. * 函数名: initLogSystem
  44. * 目标: 初始化日志系统
  45. * 返回值:
  46. * 1 表示初始化成功
  47. * 2 表示已经初始化
  48. * 0 表示初始化失败
  49. */
  50. int initLogSystem(FilePath path, LogFactoryPrintConsole print_console) {
  51. if (log_factory.init)
  52. return 2;
  53. if (strlen(path) >= 218) // 路径过长
  54. return 0;
  55. char log_path[218] = {0};
  56. char csv_path[218] = {0};
  57. log_factory.pid = getpid(); // 获取进程ID
  58. char *ti = getTime(NULL, "%Y-%m-%d%z");
  59. snprintf(log_path, 218, "%s-%s.log", path, ti);
  60. snprintf(csv_path, 218, "%s-%s.csv", path, ti);
  61. uintmax_t log_size = getFileSize(log_path);
  62. uintmax_t csv_size = getFileSize(csv_path);
  63. bool csv_head_write = (checkFile(csv_path) == 0); // 文件不存在时才写入头部
  64. log_factory.log = fopen(log_path, "a");
  65. if (log_factory.log == NULL)
  66. return 0;
  67. log_factory.csv = fopen(csv_path, "a");
  68. if (log_factory.csv == NULL)
  69. return 0;
  70. #define CSV_FORMAT "%s,%s,%ld,%ld,%s,%ld,%s,%d,%s,%s\n"
  71. #define CSV_TITLE "Level,Logger,PID,TID,Data,Timestamp,File,Line,Function,Log\n"
  72. if (csv_head_write) {
  73. fprintf(log_factory.csv, CSV_TITLE); // 设置 cvs 标题
  74. fflush(log_factory.csv);
  75. }
  76. #undef CSV_TITLE
  77. log_factory.print_console = print_console;
  78. log_factory.init = true;
  79. atexit(destructLogSystem_at_exit);
  80. initLogger(&(log_factory.sys_log), "SYSTEM", log_debug); // 设置为 debug, 记录 success 信息
  81. log_factory.sys_log.process_fatal_error = true;
  82. log_factory.sys_log.process_send_error = false;
  83. writeInfoLog(NULL, log_default, "Log system init success");
  84. writeInfoLog(NULL, log_default, "Log .log size %lld", log_size);
  85. writeInfoLog(NULL, log_default, "Log .csv size %lld", csv_size);
  86. log_factory.sys_log.level = log_error;
  87. return 1;
  88. }
  89. static void destructLogSystem_at_exit(void) {
  90. if (!log_factory.init)
  91. return;
  92. log_factory.sys_log.level = log_debug;
  93. writeInfoLog(NULL, log_default, "Log system destruct by exit.");
  94. fclose(log_factory.log);
  95. fclose(log_factory.csv);
  96. log_factory.log = NULL;
  97. log_factory.csv = NULL;
  98. log_factory.init = false;
  99. }
  100. int destructLogSystem(void) {
  101. if (!log_factory.init)
  102. return 2;
  103. log_factory.sys_log.level = log_debug;
  104. writeInfoLog(NULL, log_default, "Log system destruct by user.");
  105. fclose(log_factory.log);
  106. fclose(log_factory.csv);
  107. log_factory.log = NULL;
  108. log_factory.csv = NULL;
  109. log_factory.init = false;
  110. return 1;
  111. }
  112. void initLogger(Logger *logger, char *id, LogLevel level) {
  113. memset(logger, 0, sizeof(Logger));
  114. logger->id = id;
  115. logger->level = level;
  116. }
  117. /* LogLevel和字符串的转换 */
  118. static const char *LogLevelName[] = {
  119. "DE", // debug 0
  120. "IN", // info 1
  121. "WA", // warning 2
  122. "ER", // error 3
  123. "SE", // send_error 4
  124. "FE", // fatal_error 5
  125. };
  126. static const char *LogLevelNameLong[] = {
  127. /* 内容输出到终端时使用*/
  128. "Debug", // debug 0
  129. "Info", // info 1
  130. "Warning", // warning 2
  131. "Error", // error 3
  132. "Fatal Error", // send_error 4
  133. "*FATAL ERROR*", // fatal_error 5
  134. };
  135. static int writeLog_(Logger *logger, LogLoggerPrintConsole pc, LogLevel level, char *file, int line, char *func, char *format, va_list ap){
  136. if (logger->level > level)
  137. return 2;
  138. if (!log_factory.init || log_factory.log == NULL)
  139. return 1;
  140. if (ferror(log_factory.log))
  141. clearerr(log_factory.log);
  142. // 输出 head 信息
  143. time_t t = 0;
  144. char *ti = getTime(&t, "%Y-%m-%d %H:%M:%S");
  145. #define FORMAT "%s/[%s] %ld %ld {%s %ld} (%s:%d at %s) : '%s'\n"
  146. #define FORMAT_SHORT "%s(%s:%d) : %s\n"
  147. long tid = gettid();
  148. char tmp[2048] = {0};
  149. vsnprintf(tmp, 1024, format, ap); // ap只使用一次
  150. va_end(ap);
  151. /* 写入文件日志 */
  152. if (pc != log_print_console && log_factory.log != NULL) {
  153. fprintf(log_factory.log, FORMAT, LogLevelName[level], logger->id, log_factory.pid, tid, ti, t, file, line, func, tmp);
  154. fflush(log_factory.log);
  155. }
  156. if (pc != log_print_console && log_factory.csv != NULL) {
  157. fprintf(log_factory.csv, CSV_FORMAT, LogLevelName[level], logger->id, log_factory.pid, tid, ti, t, file, line, func, tmp);
  158. fflush(log_factory.csv);
  159. }
  160. #define STD_BUF_SIZE (strlen(tmp) + 1024)
  161. if (pc != log_print_no_console) {
  162. switch (log_factory.print_console) {
  163. case log_pc_all:
  164. if (level < log_warning) {
  165. printf_stdout(STD_BUF_SIZE, FORMAT_SHORT, LogLevelNameLong[level], file, line, tmp);
  166. fflush(stdout);
  167. } else if (log_factory.print_console) {
  168. printf_stderr(STD_BUF_SIZE, FORMAT_SHORT, LogLevelNameLong[level], file, line, tmp);
  169. fflush(stderr);
  170. }
  171. break;
  172. case log_pc_w:
  173. if (level >= log_warning) { // warning的内容一定会被打印
  174. printf_stderr(STD_BUF_SIZE, FORMAT_SHORT, LogLevelNameLong[level], file, line, tmp);
  175. fflush(stderr);
  176. }
  177. break;
  178. case log_pc_e:
  179. if (level >= log_error) { // warning的内容一定会被打印
  180. printf_stderr(STD_BUF_SIZE, FORMAT_SHORT, LogLevelNameLong[level], file, line, tmp);
  181. fflush(stderr);
  182. }
  183. break;
  184. case log_pc_quite:
  185. default:
  186. break;
  187. }
  188. }
  189. #undef STD_BUF_SIZE
  190. free(ti);
  191. #undef FORMAT
  192. #undef FORMAT_SHORT
  193. #undef CSV_FORMAT
  194. return 0;
  195. }
  196. #define CHECK_LOGGER() do {if (logger == NULL) {logger = &(log_factory.sys_log);} \
  197. if (logger == NULL || logger->id == NULL) return -1;} while(0)
  198. int writeDebugLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
  199. CHECK_LOGGER();
  200. va_list ap;
  201. va_start(ap, format);
  202. return writeLog_(logger, pc, log_debug, file, line, func, format, ap);
  203. }
  204. int writeInfoLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
  205. CHECK_LOGGER();
  206. va_list ap;
  207. va_start(ap, format);
  208. return writeLog_(logger, pc, log_info, file, line, func, format, ap);
  209. }
  210. int writeWarningLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
  211. CHECK_LOGGER();
  212. va_list ap;
  213. va_start(ap, format);
  214. return writeLog_(logger, pc, log_warning, file, line, func, format, ap);
  215. }
  216. int writeErrorLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
  217. CHECK_LOGGER();
  218. va_list ap;
  219. va_start(ap, format);
  220. return writeLog_(logger, pc, log_error, file, line, func, format, ap);
  221. }
  222. int writeSendErrorLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
  223. CHECK_LOGGER();
  224. va_list ap;
  225. va_start(ap, format);
  226. int re = writeLog_(logger, pc, log_send_error, file, line, func, format, ap);
  227. if (logger->process_send_error) {
  228. jmp_buf *buf = logger->buf;
  229. if (buf != NULL) {
  230. initLogger(logger, NULL, 0); // 清零
  231. longjmp(*buf, 1);
  232. } else
  233. exit(EXIT_FAILURE);
  234. }
  235. return re;
  236. }
  237. int writeFatalErrorLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, int exit_code, char *format, ...) {
  238. CHECK_LOGGER();
  239. va_list ap;
  240. va_start(ap, format);
  241. int re = writeLog_(logger, pc, log_fatal_error, file, line, func, format, ap);
  242. if (logger->process_fatal_error) {
  243. if (logger->exit_type == 0)
  244. abort();
  245. else
  246. exit(exit_code);
  247. }
  248. return re;
  249. }