log.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. log_LogFn fn;
  8. void *udata;
  9. int level;
  10. } Callback;
  11. static struct {
  12. void *udata;
  13. log_LockFn lock;
  14. int level;
  15. bool quiet;
  16. Callback callbacks[MAX_CALLBACKS];
  17. } L;
  18. // static const char *level_strings[] = {
  19. // "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
  20. // };
  21. static const char *level_strings[] = {
  22. "T", "D", "I", "W", "E", "F"
  23. };
  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. };
  28. #endif
  29. static void stdout_callback(log_Event *ev) {
  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. char buf[64];
  48. buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
  49. fprintf(
  50. ev->udata, "%s %-5s %s:%d: ",
  51. buf, level_strings[ev->level], ev->file, ev->line);
  52. vfprintf(ev->udata, ev->fmt, ev->ap);
  53. fprintf(ev->udata, "\n");
  54. fflush(ev->udata);
  55. }
  56. static void lock(void) {
  57. if (L.lock) { L.lock(true, L.udata); }
  58. }
  59. static void unlock(void) {
  60. if (L.lock) { L.lock(false, L.udata); }
  61. }
  62. const char* log_level_string(int level) {
  63. return level_strings[level];
  64. }
  65. void log_set_lock(log_LockFn fn, void *udata) {
  66. L.lock = fn;
  67. L.udata = udata;
  68. }
  69. void log_set_level(int level) {
  70. L.level = level;
  71. }
  72. void log_set_quiet(bool enable) {
  73. L.quiet = enable;
  74. }
  75. int log_add_callback(log_LogFn fn, void *udata, int level) {
  76. for (int i = 0; i < MAX_CALLBACKS; i++) {
  77. if (!L.callbacks[i].fn) {
  78. L.callbacks[i] = (Callback) { fn, udata, level };
  79. return 0;
  80. }
  81. }
  82. return -1;
  83. }
  84. int log_add_fp(FILE *fp, int level) {
  85. return log_add_callback(file_callback, fp, level);
  86. }
  87. static void init_event(log_Event *ev, void *udata) {
  88. if (!ev->time) {
  89. time_t t = time(NULL);
  90. ev->time = localtime(&t);
  91. }
  92. ev->udata = udata;
  93. }
  94. void log_log(int level, const char *file, int line, const char *fmt, ...) {
  95. if (level >= L.level) {
  96. va_list vl;
  97. va_start(vl, fmt);
  98. log_println_vl(level_strings[level], file, line, fmt, vl);
  99. va_end(vl);
  100. }
  101. }
  102. void log_log_x(int level, const char *file, int line, const char *fmt, ...) {
  103. log_Event ev = {
  104. .fmt = fmt,
  105. .file = file,
  106. .line = line,
  107. .level = level,
  108. };
  109. lock();
  110. if (!L.quiet && level >= L.level) {
  111. init_event(&ev, stderr);
  112. va_start(ev.ap, fmt);
  113. stdout_callback(&ev);
  114. va_end(ev.ap);
  115. }
  116. for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
  117. Callback *cb = &L.callbacks[i];
  118. if (level >= cb->level) {
  119. init_event(&ev, cb->udata);
  120. va_start(ev.ap, fmt);
  121. cb->fn(&ev);
  122. va_end(ev.ap);
  123. }
  124. }
  125. unlock();
  126. }