123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- /*
- * 文件名: log.c
- * 目标: 日志系统对aFun的API
- * 注意: 因为tool模块需要使用log系统, 因此log系统尽量少点依赖tool模块, 避免造成死循环
- * 仅依赖:
- * time_s.h 中 getTime -> strCopy
- * mem.h 中 free
- * file.h 中 getFileSize
- * stdio_.h
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include "macro.h"
- #include "mem.h"
- #include "log.h"
- #include "time_s.h"
- #include "file.h"
- #include "stdio_.h"
- #ifdef aFunWIN32
- #include <windows.h>
- #define getpid() (long)GetCurrentProcessId()
- #define gettid() (long)GetCurrentThreadId()
- // cygwin没有syscall.h, 因此需要依赖 windows 的 api
- #else
- #include <unistd.h>
- #include "sys/syscall.h"
- #define gettid() (long)syscall(SYS_gettid)
- #define getpid() (long)getpid()
- #endif
- #undef calloc
- static struct LogFactory {
- bool init; // 是否已经初始化
- long pid;
- FILE *log; // 记录文件输出的位置
- FILE *csv;
- LogFactoryPrintConsole print_console; // 输出到终端、
- Logger sys_log;
- } log_factory = {.init=false};
- static void destructLogSystem_at_exit(void);
- /*
- * 函数名: initLogSystem
- * 目标: 初始化日志系统
- * 返回值:
- * 1 表示初始化成功
- * 2 表示已经初始化
- * 0 表示初始化失败
- */
- int initLogSystem(FilePath path, LogFactoryPrintConsole print_console) {
- if (log_factory.init)
- return 2;
- if (strlen(path) >= 218) // 路径过长
- return 0;
- char log_path[218] = {0};
- char csv_path[218] = {0};
- log_factory.pid = getpid(); // 获取进程ID
- char *ti = getTime(NULL, "%Y-%m-%d%z");
- snprintf(log_path, 218, "%s-%s.log", path, ti);
- snprintf(csv_path, 218, "%s-%s.csv", path, ti);
- uintmax_t log_size = getFileSize(log_path);
- uintmax_t csv_size = getFileSize(csv_path);
- bool csv_head_write = (checkFile(csv_path) == 0); // 文件不存在时才写入头部
- log_factory.log = fopen(log_path, "a");
- if (log_factory.log == NULL)
- return 0;
- log_factory.csv = fopen(csv_path, "a");
- if (log_factory.csv == NULL)
- return 0;
- #define CSV_FORMAT "%s,%s,%ld,%ld,%s,%ld,%s,%d,%s,%s\n"
- #define CSV_TITLE "Level,Logger,PID,TID,Data,Timestamp,File,Line,Function,Log\n"
- if (csv_head_write) {
- fprintf(log_factory.csv, CSV_TITLE); // 设置 cvs 标题
- fflush(log_factory.csv);
- }
- #undef CSV_TITLE
- log_factory.print_console = print_console;
- log_factory.init = true;
- atexit(destructLogSystem_at_exit);
- initLogger(&(log_factory.sys_log), "SYSTEM", log_debug); // 设置为 debug, 记录 success 信息
- log_factory.sys_log.process_fatal_error = true;
- log_factory.sys_log.process_send_error = false;
- writeInfoLog(NULL, log_default, "Log system init success");
- writeInfoLog(NULL, log_default, "Log .log size %lld", log_size);
- writeInfoLog(NULL, log_default, "Log .csv size %lld", csv_size);
- log_factory.sys_log.level = log_error;
- return 1;
- }
- static void destructLogSystem_at_exit(void) {
- if (!log_factory.init)
- return;
- log_factory.sys_log.level = log_debug;
- writeInfoLog(NULL, log_default, "Log system destruct by exit.");
- fclose(log_factory.log);
- fclose(log_factory.csv);
- log_factory.log = NULL;
- log_factory.csv = NULL;
- log_factory.init = false;
- }
- int destructLogSystem(void) {
- if (!log_factory.init)
- return 2;
- log_factory.sys_log.level = log_debug;
- writeInfoLog(NULL, log_default, "Log system destruct by user.");
- fclose(log_factory.log);
- fclose(log_factory.csv);
- log_factory.log = NULL;
- log_factory.csv = NULL;
- log_factory.init = false;
- return 1;
- }
- void initLogger(Logger *logger, char *id, LogLevel level) {
- memset(logger, 0, sizeof(Logger));
- logger->id = id;
- logger->level = level;
- }
- /* LogLevel和字符串的转换 */
- static const char *LogLevelName[] = {
- "DE", // debug 0
- "IN", // info 1
- "WA", // warning 2
- "ER", // error 3
- "SE", // send_error 4
- "FE", // fatal_error 5
- };
- static const char *LogLevelNameLong[] = {
- /* 内容输出到终端时使用*/
- "Debug", // debug 0
- "Info", // info 1
- "Warning", // warning 2
- "Error", // error 3
- "Fatal Error", // send_error 4
- "*FATAL ERROR*", // fatal_error 5
- };
- static int writeLog_(Logger *logger, LogLoggerPrintConsole pc, LogLevel level, char *file, int line, char *func, char *format, va_list ap){
- if (logger->level > level)
- return 2;
- if (!log_factory.init || log_factory.log == NULL)
- return 1;
- if (ferror(log_factory.log))
- clearerr(log_factory.log);
- // 输出 head 信息
- time_t t = 0;
- char *ti = getTime(&t, "%Y-%m-%d %H:%M:%S");
- #define FORMAT "%s/[%s] %ld %ld {%s %ld} (%s:%d at %s) : '%s'\n"
- #define FORMAT_SHORT "%s(%s:%d) : %s\n"
- long tid = gettid();
- char tmp[2048] = {0};
- vsnprintf(tmp, 1024, format, ap); // ap只使用一次
- va_end(ap);
- /* 写入文件日志 */
- if (pc != log_print_console && log_factory.log != NULL) {
- fprintf(log_factory.log, FORMAT, LogLevelName[level], logger->id, log_factory.pid, tid, ti, t, file, line, func, tmp);
- fflush(log_factory.log);
- }
- if (pc != log_print_console && log_factory.csv != NULL) {
- fprintf(log_factory.csv, CSV_FORMAT, LogLevelName[level], logger->id, log_factory.pid, tid, ti, t, file, line, func, tmp);
- fflush(log_factory.csv);
- }
- #define STD_BUF_SIZE (strlen(tmp) + 1024)
- if (pc != log_print_no_console) {
- switch (log_factory.print_console) {
- case log_pc_all:
- if (level < log_warning) {
- printf_stdout(STD_BUF_SIZE, FORMAT_SHORT, LogLevelNameLong[level], file, line, tmp);
- fflush(stdout);
- } else if (log_factory.print_console) {
- printf_stderr(STD_BUF_SIZE, FORMAT_SHORT, LogLevelNameLong[level], file, line, tmp);
- fflush(stderr);
- }
- break;
- case log_pc_w:
- if (level >= log_warning) { // warning的内容一定会被打印
- printf_stderr(STD_BUF_SIZE, FORMAT_SHORT, LogLevelNameLong[level], file, line, tmp);
- fflush(stderr);
- }
- break;
- case log_pc_e:
- if (level >= log_error) { // warning的内容一定会被打印
- printf_stderr(STD_BUF_SIZE, FORMAT_SHORT, LogLevelNameLong[level], file, line, tmp);
- fflush(stderr);
- }
- break;
- case log_pc_quite:
- default:
- break;
- }
- }
- #undef STD_BUF_SIZE
- free(ti);
- #undef FORMAT
- #undef FORMAT_SHORT
- #undef CSV_FORMAT
- return 0;
- }
- #define CHECK_LOGGER() do {if (logger == NULL) {logger = &(log_factory.sys_log);} \
- if (logger == NULL || logger->id == NULL) return -1;} while(0)
- int writeDebugLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
- CHECK_LOGGER();
- va_list ap;
- va_start(ap, format);
- return writeLog_(logger, pc, log_debug, file, line, func, format, ap);
- }
- int writeInfoLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
- CHECK_LOGGER();
- va_list ap;
- va_start(ap, format);
- return writeLog_(logger, pc, log_info, file, line, func, format, ap);
- }
- int writeWarningLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
- CHECK_LOGGER();
- va_list ap;
- va_start(ap, format);
- return writeLog_(logger, pc, log_warning, file, line, func, format, ap);
- }
- int writeErrorLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
- CHECK_LOGGER();
- va_list ap;
- va_start(ap, format);
- return writeLog_(logger, pc, log_error, file, line, func, format, ap);
- }
- int writeSendErrorLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, char *format, ...) {
- CHECK_LOGGER();
- va_list ap;
- va_start(ap, format);
- int re = writeLog_(logger, pc, log_send_error, file, line, func, format, ap);
- if (logger->process_send_error) {
- jmp_buf *buf = logger->buf;
- if (buf != NULL) {
- initLogger(logger, NULL, 0); // 清零
- longjmp(*buf, 1);
- } else
- exit(EXIT_FAILURE);
- }
- return re;
- }
- int writeFatalErrorLog_(Logger *logger, LogLoggerPrintConsole pc, char *file, int line, char *func, int exit_code, char *format, ...) {
- CHECK_LOGGER();
- va_list ap;
- va_start(ap, format);
- int re = writeLog_(logger, pc, log_fatal_error, file, line, func, format, ap);
- if (logger->process_fatal_error) {
- if (logger->exit_type == 0)
- abort();
- else
- exit(exit_code);
- }
- return re;
- }
|