log.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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. * str.h
  11. * exit_.h
  12. */
  13. #include <cstdio>
  14. #include <cstdlib>
  15. #include <cstdarg>
  16. #include <cstring>
  17. #include "tool-type.h"
  18. #include "log.h"
  19. #include "tool-exception.h"
  20. #include "log-macro.h"
  21. #include "tool-time.h"
  22. #include "file.h"
  23. #include "tool-stdio.h"
  24. #include "str.h"
  25. #include "tool-exit.h"
  26. #ifdef aFunWIN32
  27. #include <Windows.h>
  28. #define getpid() static_cast<long>(GetCurrentProcessId())
  29. #define gettid() static_cast<long>(GetCurrentThreadId())
  30. // cygwin没有syscall.h, 因此需要依赖 windows 的 api
  31. #else
  32. #include <unistd.h>
  33. #include "sys/syscall.h"
  34. #define gettid() static_cast<long>(syscall(SYS_gettid))
  35. #define getpid() static_cast<long>(getpid())
  36. #endif
  37. namespace aFuntool {
  38. typedef struct LogNode LogNode;
  39. struct LogNode { // 日志信息记录节点
  40. LogLevel level = log_info;
  41. const char *id = "SYSTEM";
  42. pid_t tid = 0;
  43. char *date = nullptr; // 需要释放
  44. time_t time = 0;
  45. const char *file = "unknown";
  46. int line = 1;
  47. const char *func = "unknown";
  48. char *info = nullptr; // 需要释放
  49. LogNode *next = nullptr;
  50. };
  51. void staticAnsyWritrLog(LogFactory::ansyData *data);
  52. LogFactory::LogFactory(const aFuntool::FilePath &path, bool is_async) noexcept(false)
  53. : sys_log{*this, "SYSTEM", log_info}{
  54. std::unique_lock<std::mutex> ul{mutex_};
  55. char log_path[218] = {0};
  56. char csv_path[218] = {0};
  57. pid_ = getpid(); // 获取进程ID
  58. char *ti = getTime(nullptr, (char *) "%Y-%m-%d%z");
  59. snprintf(log_path, 218, "%s-%s.log", path.c_str(), ti);
  60. snprintf(csv_path, 218, "%s-%s.csv", path.c_str(), ti);
  61. safeFree(ti);
  62. uintmax_t log_size = getFileSize(log_path);
  63. uintmax_t csv_size = getFileSize(csv_path);
  64. bool csv_head_write = (checkFile(csv_path) == 0); // 文件不存在时才写入头部
  65. log_ = fileOpen(log_path, "a");
  66. if (log_ == nullptr)
  67. throw FileOpenException(log_path);
  68. csv_ = fileOpen(csv_path, (char *) "a");
  69. if (csv_ == nullptr)
  70. throw FileOpenException(csv_path);
  71. #define CSV_FORMAT "%s,%s,%d,%d,%s,%lld,%s,%d,%s,%s\n"
  72. #define CSV_TITLE "Level,Logger,PID,TID,Data,Timestamp,File,Line,Function,Log\n"
  73. if (csv_head_write) {
  74. fprintf(csv_, CSV_TITLE); // 设置 cvs 标题
  75. fflush(csv_);
  76. }
  77. #undef CSV_TITLE
  78. init_ = true;
  79. async_ = is_async;
  80. if (is_async) {
  81. log_buf_ = nullptr;
  82. plog_buf_ = &log_buf_;
  83. auto *data = new ansyData{*this, mutex_};
  84. thread_ = std::thread(staticAnsyWritrLog, data);
  85. }
  86. ul.unlock();
  87. infoLog(&this->sys_log, "Log system init success");
  88. infoLog(&this->sys_log, "Log .log size %lld", log_size);
  89. infoLog(&this->sys_log, "Log .csv size %lld", csv_size);
  90. }
  91. LogFactory::~LogFactory(){
  92. std::unique_lock<std::mutex> ul{mutex_};
  93. ul.unlock();
  94. infoLog(&this->sys_log, "Log system destruct by exit."); // 需要用锁
  95. ul.lock();
  96. init_ = false;
  97. if (async_) {
  98. ul.unlock();
  99. cond_.notify_all();
  100. thread_.join();
  101. ul.lock();
  102. if (log_buf_ != nullptr)
  103. printf_stderr(0, "Logsystem destruct error.");
  104. }
  105. fileClose(log_);
  106. fileClose(csv_);
  107. log_ = nullptr;
  108. csv_ = nullptr;
  109. }
  110. /* LogLevel和字符串的转换 */
  111. const char *LogLevelName[] = {
  112. "TK", // track 0
  113. "DE", // debug 1
  114. "IN", // info 2
  115. "WA", // warning 3
  116. "ER", // error 4
  117. "SE", // send_error 5
  118. "FE", // fatal_error 6
  119. };
  120. const char *LogLevelNameLong[] = {
  121. /* 内容输出到终端时使用*/
  122. "Track", // track 0
  123. "Debug", // debug 1
  124. "Info", // info 2
  125. "Warning", // warning 3
  126. "Error", // error 4
  127. "Fatal Error", // send_error 5
  128. "*FATAL ERROR*", // fatal_error 6
  129. };
  130. /**
  131. * 日志写入到文件
  132. * @param level 日志等级
  133. * @param id 日志器ID
  134. * @param tid 线程号
  135. * @param ti 时间
  136. * @param t 时间戳
  137. * @param file 文件名
  138. * @param line 行号
  139. * @param func 函数名
  140. * @param info 日志内容
  141. */
  142. void LogFactory::writeLog(LogLevel level,
  143. const char *id, pid_t tid,
  144. const char *ti, time_t t,
  145. const char *file, int line, const char *func,
  146. const char *info){
  147. #define FORMAT "%s/[%s] %d %d {%s %lld} (%s:%d at %s) : '%s' \n"
  148. /* 写入文件日志 */
  149. if (log_ != nullptr) {
  150. fprintf(log_, FORMAT, LogLevelName[level], id, pid_, tid, ti, static_cast<long long>(t), file, line, func, info);
  151. fflush(log_);
  152. }
  153. if (csv_ != nullptr) {
  154. fprintf(csv_, CSV_FORMAT, LogLevelName[level], id, pid_, tid, ti, static_cast<long long>(t), file, line, func, info);
  155. fflush(csv_);
  156. }
  157. #undef FORMAT
  158. #undef CSV_FORMAT
  159. }
  160. /**
  161. * 日志写入到控制台
  162. * @param level 日志等级
  163. * @param id 日志器ID
  164. * @param tid 线程号
  165. * @param ti 时间
  166. * @param t 时间戳
  167. * @param file 文件名
  168. * @param line 行号
  169. * @param func 函数名
  170. * @param info 日志内容
  171. */
  172. void LogFactory::writeConsole(LogLevel level,
  173. const char *id, pid_t tid,
  174. const char *ti, time_t t,
  175. const char *file, int line, const char *func,
  176. const char *info){
  177. if (level < log_warning) {
  178. cout << "\r* " << LogLevelName[level] << "/[" << id << "] " << tid;
  179. cout << " " << t << " " << ti << " (" << file << ":" << line << ") : '" << info << "'\n";
  180. fflush(stdout);
  181. } else {
  182. cerr << "\r* " << LogLevelName[level] << "/[" << id << "] " << tid;
  183. cerr << " " << t << " " << ti << " (" << file << ":" << line << ") : '" << info << "'\n";
  184. fflush(stderr);
  185. }
  186. }
  187. /**
  188. * 日志异步写入
  189. * @param level 日志等级
  190. * @param id 日志器ID
  191. * @param tid 线程号
  192. * @param ti 时间
  193. * @param t 时间戳
  194. * @param file 文件名
  195. * @param line 行号
  196. * @param func 函数名
  197. * @param info 日志内容
  198. */
  199. void LogFactory::writeLogAsyn(LogLevel level,
  200. const char *id, pid_t tid,
  201. const char *ti, time_t t,
  202. const char *file, int line, const char *func, const char *info){
  203. #define D(i) (*(plog_buf_))->i
  204. *(plog_buf_) = new LogNode;
  205. D(level) = level;
  206. D(id) = id;
  207. D(tid) = tid;
  208. D(date) = strCopy(ti);
  209. D(time) = t;
  210. D(file) = file;
  211. D(line) = line;
  212. D(func) = func;
  213. D(info) = strCopy(info);
  214. plog_buf_ = &(D(next));
  215. #undef D
  216. }
  217. LogNode *LogFactory::pop(){
  218. struct LogNode *n = log_buf_;
  219. if (n != nullptr) {
  220. log_buf_ = n->next;
  221. if (log_buf_ == nullptr)
  222. plog_buf_ = &log_buf_;
  223. }
  224. return n;
  225. }
  226. void staticAnsyWritrLog(LogFactory::ansyData *data){
  227. data->factor.ansyWritrLog(data);
  228. }
  229. /**
  230. * 异步写入日志程序
  231. * @return
  232. */
  233. void LogFactory::ansyWritrLog(ansyData *data){
  234. std::unique_lock<std::mutex> ul{mutex_};
  235. while (true) {
  236. while (init_ && log_buf_ == nullptr)
  237. cond_.wait(ul);
  238. if (!init_ && log_buf_ == nullptr)
  239. break;
  240. LogNode *tmp = data->factor.pop();
  241. #define D(i) tmp->i
  242. data->factor.writeLog(D(level), D(id), D(tid), D(date), D(time), D(file), D(line), D(func), D(info));
  243. #undef D
  244. safeFree(tmp->date);
  245. safeFree(tmp->info);
  246. delete tmp;
  247. }
  248. delete data;
  249. }
  250. /**
  251. * 日志器 写入日志
  252. * @param logger 日志器
  253. * @param pc 是否写入到控制台
  254. * @param level 日志等级
  255. * @param file 文件名
  256. * @param line 行号
  257. * @param func 函数名
  258. * @param format 日志内容(格式字符串)
  259. * @param ap 格式字符串内容
  260. * @return
  261. */
  262. int LogFactory::newLog(Logger *logger,
  263. bool pc,
  264. LogLevel level,
  265. const char *file, int line, const char *func,
  266. const char *format, va_list ap){
  267. if (logger->level_ > level)
  268. return 2;
  269. std::unique_lock<std::mutex> ul{mutex_};
  270. if (!init_ || log_ == nullptr) {
  271. return 1;
  272. }
  273. clear_ferror(log_);
  274. // 输出 head 信息
  275. time_t t = 0;
  276. char *ti = getTime(&t, ("%Y-%m-%d %H:%M:%S"));
  277. pid_t tid = gettid();
  278. char tmp[2048] = {0};
  279. vsnprintf(tmp, 1024, format, ap); // ap只使用一次
  280. va_end(ap);
  281. if (async_)
  282. writeLogAsyn(level, logger->id_.c_str(), tid, ti, t, file, line, func, tmp);
  283. else
  284. writeLog(level, logger->id_.c_str(), tid, ti, t, file, line, func, tmp);
  285. if (pc)
  286. writeConsole(level, logger->id_.c_str(), tid, ti, t, file, line, func, tmp);
  287. ul.unlock();
  288. if (async_)
  289. cond_.notify_all();
  290. safeFree(ti);
  291. return 0;
  292. }
  293. #undef trackLog
  294. int Logger::writeTrackLog(const char *file, int line, const char *func,
  295. const char *format, ...){
  296. #if aFunWriteTrack
  297. va_list ap;
  298. va_start(ap, format);
  299. return factor_.newLog(this, aFunConsoleTrack, log_track, file, line, func, format, ap);
  300. #endif
  301. }
  302. #undef debugLog
  303. int Logger::writeDebugLog(const char *file, int line, const char *func,
  304. const char *format, ...){
  305. #if aFunWriteDebug
  306. va_list ap;
  307. va_start(ap, format);
  308. return factor_.newLog(this, aFunConsoleDebug, log_debug, file, line, func, format, ap);
  309. #endif
  310. }
  311. #undef infoLog
  312. int Logger::writeInfoLog(const char *file, int line, const char *func,
  313. const char *format, ...){
  314. #if aFunWriteInfo
  315. va_list ap;
  316. va_start(ap, format);
  317. return factor_.newLog(this, aFunConsoleInfo, log_info, file, line, func, format, ap);
  318. #endif
  319. }
  320. #undef warningLog
  321. int Logger::writeWarningLog(const char *file, int line, const char *func,
  322. const char *format, ...){
  323. #if !aFunIgnoreWarning
  324. va_list ap;
  325. va_start(ap, format);
  326. return factor_.newLog(this, aFunConsoleWarning, log_warning, file, line, func, format, ap);
  327. #endif
  328. }
  329. #undef errorLog
  330. int Logger::writeErrorLog(const char *file, int line, const char *func,
  331. const char *format, ...){
  332. #if !aFunIgnoreError
  333. va_list ap;
  334. va_start(ap, format);
  335. return factor_.newLog(this, aFunConsoleError, log_error, file, line, func, format, ap);
  336. #endif
  337. }
  338. #undef sendErrorLog
  339. int Logger::writeSendErrorLog(const char *file, int line, const char *func,
  340. const char *format, ...) noexcept(false) {
  341. #ifndef aFunOFFAllLog
  342. #if !aFunIgnoreSendError
  343. va_list ap;
  344. va_start(ap, format);
  345. factor_.newLog(this, aFunConsoleSendError, log_send_error, file, line, func, format, ap);
  346. #endif
  347. if (this->exit_)
  348. throw LogFatalError("Log Fatal Error");
  349. aFunExit(EXIT_FAILURE);
  350. #endif
  351. return 0;
  352. }
  353. #undef fatalErrorLog
  354. int Logger::writeFatalErrorLog(const char *file, int line, const char *func,
  355. int exit_code, const char *format, ...) noexcept(false){
  356. #ifndef aFunOFFAllLog
  357. #if !aFunIgnoreFatal
  358. va_list ap;
  359. va_start(ap, format);
  360. this->factor_.newLog(this, aFunConsoleFatalError, log_fatal_error, file, line, func, format, ap);
  361. #endif
  362. if (exit_code == EXIT_SUCCESS)
  363. abort();
  364. else
  365. aFunExit(exit_code);
  366. #endif
  367. return 0;
  368. }
  369. }