logger.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * Logger Copyright 2013 Regents of the University of Michigan
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy
  6. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  7. */
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <assert.h>
  13. #include <sys/time.h>
  14. #include <time.h>
  15. #include <syslog.h>
  16. #include <math.h>
  17. #include <pthread.h>
  18. #include "logger.h"
  19. #include "xalloc.h"
  20. #include "lockfd.h"
  21. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  22. static enum LogLevel log_output_level = ZLOG_INFO;
  23. static FILE *log_output_stream = NULL;
  24. static int color = 0;
  25. static const char *log_level_name[] = {
  26. "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
  27. #define RED "\x1b[31m"
  28. #define GREEN "\x1b[32m"
  29. #define YELLOW "\x1b[33m"
  30. #define BLUE "\x1b[34m"
  31. #define MAGENTA "\x1b[35m"
  32. #define CYAN "\x1b[36m"
  33. #define RESET "\033[0m"
  34. #define COLOR(x) do { if(color) fprintf(log_output_stream, "%s", x); } while (0)
  35. static const char* color_for_level(enum LogLevel level)
  36. {
  37. switch(level) {
  38. case ZLOG_FATAL:
  39. return RED;
  40. case ZLOG_ERROR:
  41. return MAGENTA;
  42. case ZLOG_WARN:
  43. return YELLOW;
  44. case ZLOG_INFO:
  45. return GREEN;
  46. case ZLOG_DEBUG:
  47. return BLUE;
  48. case ZLOG_TRACE:
  49. return RESET;
  50. default:
  51. return RESET;
  52. }
  53. }
  54. static int LogLogVA(enum LogLevel level, const char *loggerName,
  55. const char *logMessage, va_list args)
  56. {
  57. if (!log_output_stream) {
  58. log_output_stream = stderr;
  59. }
  60. // if logging to a shared output channel, then use a global
  61. // lock accross ZMap. Otherwise, if we're logging to a file,
  62. // only lockin with the module, in order to avoid having
  63. // corrupt log entries.
  64. if (log_output_stream == stdout || log_output_stream == stderr) {
  65. lock_file(log_output_stream);
  66. } else {
  67. pthread_mutex_lock(&mutex);
  68. }
  69. if (color) {
  70. COLOR(color_for_level(level));
  71. }
  72. if (level <= log_output_level) {
  73. const char *levelName = log_level_name[level];
  74. struct timeval now;
  75. char timestamp[256];
  76. gettimeofday(&now, NULL);
  77. time_t sec = now.tv_sec;
  78. struct tm* ptm = localtime(&sec);
  79. strftime(timestamp, 20, "%b %d %H:%M:%S", ptm);
  80. fprintf(log_output_stream, "%s.%03ld [%s] ",
  81. timestamp, (long) now.tv_usec/1000, levelName);
  82. if (loggerName) {
  83. fprintf(log_output_stream, "%s: ", loggerName);
  84. }
  85. if (logMessage) {
  86. vfprintf(log_output_stream, logMessage, args);
  87. }
  88. if (loggerName || logMessage) {
  89. fputs("\n", log_output_stream);
  90. }
  91. }
  92. if (color) {
  93. COLOR(RESET);
  94. }
  95. fflush(log_output_stream);
  96. if (log_output_stream == stdout || log_output_stream == stderr) {
  97. unlock_file(log_output_stream);
  98. } else {
  99. pthread_mutex_unlock(&mutex);
  100. }
  101. return EXIT_SUCCESS;
  102. }
  103. int log_fatal(const char *name, const char *message, ...) {
  104. va_list va;
  105. va_start(va, message);
  106. LogLogVA(ZLOG_FATAL, name, message, va);
  107. va_end(va);
  108. va_start(va, message);
  109. vsyslog(LOG_MAKEPRI(LOG_USER, LOG_CRIT), message, va);
  110. va_end(va);
  111. exit(EXIT_FAILURE);
  112. }
  113. int log_error(const char *name, const char *message, ...) {
  114. va_list va;
  115. va_start(va, message);
  116. int ret = LogLogVA(ZLOG_ERROR, name, message, va);
  117. va_end(va);
  118. va_start(va, message);
  119. vsyslog(LOG_MAKEPRI(LOG_USER, LOG_ERR), message, va);
  120. va_end(va);
  121. return ret;
  122. }
  123. int log_warn(const char *name, const char *message, ...) {
  124. va_list va;
  125. va_start(va, message);
  126. int ret = LogLogVA(ZLOG_WARN, name, message, va);
  127. va_end(va);
  128. va_start(va, message);
  129. vsyslog(LOG_MAKEPRI(LOG_USER, LOG_WARNING), message, va);
  130. va_end(va);
  131. return ret;
  132. }
  133. int log_info(const char *name, const char *message, ...) {
  134. va_list va;
  135. va_start(va, message);
  136. int ret = LogLogVA(ZLOG_INFO, name, message, va);
  137. va_end(va);
  138. char *prefixed = xmalloc(strlen(name) + strlen(message) + 3);
  139. strcpy(prefixed, name);
  140. strcat(prefixed, ": ");
  141. strcat(prefixed, message);
  142. va_start(va, message);
  143. vsyslog(LOG_MAKEPRI(LOG_USER, LOG_INFO), prefixed, va);
  144. va_end(va);
  145. free(prefixed);
  146. return ret;
  147. }
  148. int log_debug(const char *name, const char *message, ...) {
  149. va_list va;
  150. va_start(va, message);
  151. int ret = LogLogVA(ZLOG_DEBUG, name, message, va);
  152. va_end(va);
  153. char *prefixed = xmalloc(strlen(name) + strlen(message) + 3);
  154. strcpy(prefixed, name);
  155. strcat(prefixed, ": ");
  156. strcat(prefixed, message);
  157. va_start(va, message);
  158. vsyslog(LOG_MAKEPRI(LOG_USER, LOG_DEBUG), prefixed, va);
  159. va_end(va);
  160. free(prefixed);
  161. return ret;
  162. }
  163. extern int log_trace(const char *name, const char *message, ...) {
  164. va_list va;
  165. va_start(va, message);
  166. int ret = LogLogVA(ZLOG_TRACE, name, message, va);
  167. va_end(va);
  168. char *prefixed = xmalloc(strlen(name) + strlen(message) + 3);
  169. strcpy(prefixed, name);
  170. strcat(prefixed, ": ");
  171. strcat(prefixed, message);
  172. va_start(va, message);
  173. vsyslog(LOG_MAKEPRI(LOG_USER, LOG_DEBUG), prefixed, va);
  174. va_end(va);
  175. free(prefixed);
  176. return ret;
  177. }
  178. int log_init(FILE *stream, enum LogLevel level,
  179. int syslog_enabled, const char *appname)
  180. {
  181. log_output_stream = stream;
  182. log_output_level = level;
  183. if (syslog_enabled) {
  184. openlog(appname, 0, LOG_USER); //no options
  185. }
  186. if (isatty(fileno(log_output_stream))) {
  187. color = 1;
  188. }
  189. return 0;
  190. }
  191. void check_and_log_file_error(FILE *file, const char*name)
  192. {
  193. if (ferror(file)) {
  194. log_fatal(name, "unable to write to file");
  195. }
  196. }
  197. double now(void)
  198. {
  199. struct timeval now;
  200. gettimeofday(&now, NULL);
  201. return (double)now.tv_sec + (double)now.tv_usec/1000000.;
  202. }
  203. size_t dstrftime(char *buf, size_t maxsize, const char *format, double tm)
  204. {
  205. struct timeval tv;
  206. double tm_floor;
  207. tm_floor = floor(tm);
  208. tv.tv_sec = (long) tm_floor;
  209. tv.tv_usec = (long) (tm - floor(tm)) * 1000000;
  210. return strftime(buf, maxsize, format, localtime((const time_t*) &tv));
  211. }