log.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. /**
  5. * \file log.c
  6. *
  7. * \brief Functions to send messages to log files or the console.
  8. */
  9. #include <stdarg.h>
  10. #include <assert.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include "orconfig.h"
  14. #include "./util.h"
  15. #include "./log.h"
  16. #ifdef MS_WINDOWS
  17. #define vsnprintf _vsnprintf
  18. #define snprintf _snprintf
  19. #endif
  20. /** Information for a single logfile; only used in log.c */
  21. typedef struct logfile_t {
  22. struct logfile_t *next; /**< Next logfile_t in the linked list. */
  23. char *filename; /**< Filename to open. */
  24. FILE *file; /**< Stream to receive log messages. */
  25. int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
  26. int loglevel; /**< Lowest severity level to send to this stream. */
  27. int max_loglevel; /**< Highest severity level to send to this stream. */
  28. int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
  29. } logfile_t;
  30. /** Helper: map a log severity to descriptive string. */
  31. static INLINE const char *sev_to_string(int severity) {
  32. switch(severity) {
  33. case LOG_DEBUG: return "debug";
  34. case LOG_INFO: return "info";
  35. case LOG_NOTICE: return "notice";
  36. case LOG_WARN: return "warn";
  37. case LOG_ERR: return "err";
  38. default: assert(0); return "UNKNOWN";
  39. }
  40. }
  41. /** Linked list of logfile_t. */
  42. static logfile_t *logfiles = NULL;
  43. /** Helper: Format a log message into a fixed-sized buffer. (This is
  44. * factored out of <b>logv</b> so that we never format a message more
  45. * than once.)
  46. */
  47. static INLINE void format_msg(char *buf, size_t buf_len,
  48. int severity, const char *funcname,
  49. const char *format, va_list ap)
  50. {
  51. time_t t;
  52. struct timeval now;
  53. size_t n;
  54. buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
  55. tor_gettimeofday(&now);
  56. t = (time_t)now.tv_sec;
  57. n = strftime(buf, buf_len, "%b %d %H:%M:%S", localtime(&t));
  58. n += snprintf(buf+n, buf_len-n,
  59. ".%.3ld [%s] ",
  60. (long)now.tv_usec / 1000, sev_to_string(severity));
  61. if(n > buf_len)
  62. n = buf_len-1; /* the *nprintf funcs return how many bytes they
  63. * _would_ print, if the output is truncated.
  64. * Subtract one because the count doesn't include the \0 */
  65. if (funcname) {
  66. n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
  67. if(n > buf_len)
  68. n = buf_len-1;
  69. }
  70. n += vsnprintf(buf+n,buf_len-n,format,ap);
  71. if(n > buf_len)
  72. n = buf_len-1;
  73. buf[n]='\n';
  74. buf[n+1]='\0';
  75. }
  76. /** Helper: sends a message to the appropriate logfiles, at loglevel
  77. * <b>severity</b>. If provided, <b>funcname</b> is prepended to the
  78. * message. The actual message is derived as from vsprintf(format,ap).
  79. */
  80. static void
  81. logv(int severity, const char *funcname, const char *format, va_list ap)
  82. {
  83. char buf[10024];
  84. int formatted = 0;
  85. logfile_t *lf;
  86. assert(format);
  87. for (lf = logfiles; lf; lf = lf->next) {
  88. if (severity < lf->loglevel || severity > lf->max_loglevel)
  89. continue;
  90. if (!lf->file)
  91. continue;
  92. if (!formatted) {
  93. format_msg(buf, 10024, severity, funcname, format, ap);
  94. formatted = 1;
  95. }
  96. if(fputs(buf, lf->file) == EOF) { /* error */
  97. assert(0); /* XXX */
  98. }
  99. if(fflush(lf->file) == EOF) { /* error */
  100. /* don't log the error! */
  101. assert(0); /* XXX fail for now. what's better to do? */
  102. }
  103. }
  104. }
  105. /** Output a message to the log. */
  106. void _log(int severity, const char *format, ...)
  107. {
  108. va_list ap;
  109. va_start(ap,format);
  110. logv(severity, NULL, format, ap);
  111. va_end(ap);
  112. }
  113. /** Output a message to the log, prefixed with a function name <b>fn</b>. */
  114. void _log_fn(int severity, const char *fn, const char *format, ...)
  115. {
  116. va_list ap;
  117. va_start(ap,format);
  118. logv(severity, fn, format, ap);
  119. va_end(ap);
  120. }
  121. /** Close all open log files. */
  122. void close_logs()
  123. {
  124. logfile_t *victim;
  125. while(logfiles) {
  126. victim = logfiles;
  127. logfiles = logfiles->next;
  128. if (victim->needs_close)
  129. fclose(victim->file);
  130. tor_free(victim->filename);
  131. tor_free(victim);
  132. }
  133. }
  134. /** Close and re-open all log files; used to rotate logs on SIGHUP. */
  135. void reset_logs()
  136. {
  137. logfile_t *lf;
  138. for (lf = logfiles; lf; lf = lf->next) {
  139. if (lf->needs_close) {
  140. fclose(lf->file);
  141. lf->file = fopen(lf->filename, "a");
  142. }
  143. }
  144. }
  145. /** Add a log handler to send all messages of severity <b>loglevel</b>
  146. * or higher to <b>stream</b>. */
  147. void add_stream_log(int loglevelMin, int loglevelMax, const char *name, FILE *stream)
  148. {
  149. logfile_t *lf;
  150. lf = tor_malloc(sizeof(logfile_t));
  151. lf->filename = tor_strdup(name);
  152. lf->needs_close = 0;
  153. lf->loglevel = loglevelMin;
  154. lf->max_loglevel = loglevelMax;
  155. lf->file = stream;
  156. lf->next = logfiles;
  157. lf->is_temporary = 0;
  158. logfiles = lf;
  159. }
  160. /** Add a log handler to receive messages during startup (before the real
  161. * logs are initialized).
  162. */
  163. void add_temp_log(void)
  164. {
  165. add_stream_log(LOG_INFO, LOG_ERR, "<temp>", stdout);
  166. logfiles->is_temporary = 1;
  167. }
  168. void close_temp_logs(void)
  169. {
  170. logfile_t *lf, **p;
  171. for (p = &logfiles; *p; ) {
  172. if ((*p)->is_temporary) {
  173. lf = *p;
  174. *p = (*p)->next;
  175. if (lf->needs_close)
  176. fclose(lf->file);
  177. tor_free(lf->filename);
  178. tor_free(lf);
  179. } else {
  180. p = &((*p)->next);
  181. }
  182. }
  183. }
  184. /**
  185. * Add a log handler to send messages to <b>filename</b>. If opening
  186. * the logfile fails, -1 is returned and errno is set appropriately
  187. * (by fopen).
  188. */
  189. int add_file_log(int loglevelMin, int loglevelMax, const char *filename)
  190. {
  191. FILE *f;
  192. f = fopen(filename, "a");
  193. if (!f) return -1;
  194. add_stream_log(loglevelMin, loglevelMax, filename, f);
  195. logfiles->needs_close = 1;
  196. return 0;
  197. }
  198. /** If <b>level</b> is a valid log severity, return the corresponding
  199. * numeric value. Otherwise, return -1. */
  200. int parse_log_level(const char *level) {
  201. if (!strcasecmp(level, "err"))
  202. return LOG_ERR;
  203. else if (!strcasecmp(level, "notice"))
  204. return LOG_NOTICE;
  205. else if (!strcasecmp(level, "info"))
  206. return LOG_INFO;
  207. else if (!strcasecmp(level, "debug"))
  208. return LOG_DEBUG;
  209. else
  210. return -1;
  211. }
  212. int get_min_log_level(void)
  213. {
  214. logfile_t *lf;
  215. int min = LOG_ERR;
  216. for (lf = logfiles; lf; lf = lf->next) {
  217. if (lf->loglevel < min)
  218. min = lf->loglevel;
  219. }
  220. return min;
  221. }
  222. /*
  223. Local Variables:
  224. mode:c
  225. indent-tabs-mode:nil
  226. c-basic-offset:2
  227. End:
  228. */