log.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #include <string.h>
  2. #include <stdarg.h>
  3. #include "log.h"
  4. #include "ab_code.h"
  5. #define MAX_CALLBACKS 32
  6. typedef struct
  7. {
  8. log_LogFn fn;
  9. void *udata;
  10. int level;
  11. } Callback;
  12. static struct
  13. {
  14. void *udata;
  15. log_LockFn lock;
  16. int level;
  17. bool quiet;
  18. Callback callbacks[MAX_CALLBACKS];
  19. } L;
  20. static const char *level_strings[] = {
  21. "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
  22. static const char *level_chars[] = {
  23. "T", "D", "I", "W", "E", "F"};
  24. #ifdef LOG_USE_COLOR
  25. static const char *level_colors[] = {
  26. "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
  27. #endif
  28. static void stdout_callback(log_Event *ev)
  29. {
  30. char buf[16];
  31. buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
  32. #ifdef LOG_USE_COLOR
  33. fprintf(
  34. ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
  35. buf, level_colors[ev->level], level_strings[ev->level],
  36. ev->file, ev->line);
  37. #else
  38. fprintf(
  39. ev->udata, "%s %-5s %s:%d: ",
  40. buf, level_strings[ev->level], ev->file, ev->line);
  41. #endif
  42. vfprintf(ev->udata, ev->fmt, ev->ap);
  43. fprintf(ev->udata, "\n");
  44. fflush(ev->udata);
  45. }
  46. static void file_callback(log_Event *ev)
  47. {
  48. char buf[64];
  49. buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
  50. fprintf(
  51. ev->udata, "%s %-5s %s:%d: ",
  52. buf, level_strings[ev->level], ev->file, ev->line);
  53. vfprintf(ev->udata, ev->fmt, ev->ap);
  54. fprintf(ev->udata, "\n");
  55. fflush(ev->udata);
  56. }
  57. static void lock(void)
  58. {
  59. if (L.lock)
  60. {
  61. L.lock(true, L.udata);
  62. }
  63. }
  64. static void unlock(void)
  65. {
  66. if (L.lock)
  67. {
  68. L.lock(false, L.udata);
  69. }
  70. }
  71. const char *log_level_string(int level)
  72. {
  73. return level_strings[level];
  74. }
  75. void log_set_lock(log_LockFn fn, void *udata)
  76. {
  77. L.lock = fn;
  78. L.udata = udata;
  79. }
  80. void log_set_level(int level)
  81. {
  82. L.level = level;
  83. }
  84. void log_set_quiet(bool enable)
  85. {
  86. L.quiet = enable;
  87. }
  88. int log_add_callback(log_LogFn fn, void *udata, int level)
  89. {
  90. for (int i = 0; i < MAX_CALLBACKS; i++)
  91. {
  92. if (!L.callbacks[i].fn)
  93. {
  94. L.callbacks[i] = (Callback){fn, udata, level};
  95. return 0;
  96. }
  97. }
  98. return -1;
  99. }
  100. int log_add_fp(FILE *fp, int level)
  101. {
  102. return log_add_callback(file_callback, fp, level);
  103. }
  104. static void init_event(log_Event *ev, void *udata)
  105. {
  106. if (!ev->time)
  107. {
  108. time_t t = time(NULL);
  109. ev->time = localtime(&t);
  110. }
  111. ev->udata = udata;
  112. }
  113. void log_log(int level, const char *file, int line, const char *fmt, ...)
  114. {
  115. if (level < LOG_TRACE || level > LOG_FATAL)
  116. {
  117. return;
  118. }
  119. if (ablog_print())
  120. {
  121. if (ablog_file() && level >= L.level)
  122. {
  123. va_list vl;
  124. va_start(vl, fmt);
  125. log_println_vl(1, level_chars[level], file, line, fmt, vl);
  126. va_end(vl);
  127. }
  128. if (ablog_stdout() && level >= L.level)
  129. {
  130. va_list vl;
  131. va_start(vl, fmt);
  132. log_println_vl(0, level_chars[level], file, line, fmt, vl);
  133. va_end(vl);
  134. }
  135. }
  136. log_Event ev = {
  137. .fmt = fmt,
  138. .file = file,
  139. .line = line,
  140. .level = level,
  141. };
  142. lock();
  143. if (!L.quiet && level >= L.level)
  144. {
  145. init_event(&ev, stderr);
  146. va_start(ev.ap, fmt);
  147. stdout_callback(&ev);
  148. va_end(ev.ap);
  149. }
  150. for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++)
  151. {
  152. Callback *cb = &L.callbacks[i];
  153. if (level >= cb->level)
  154. {
  155. init_event(&ev, cb->udata);
  156. va_start(ev.ap, fmt);
  157. cb->fn(&ev);
  158. va_end(ev.ap);
  159. }
  160. }
  161. unlock();
  162. }