log.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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. static INLINE size_t _log_prefix(char *buf, size_t buf_len, int severity)
  44. {
  45. time_t t;
  46. struct timeval now;
  47. size_t n;
  48. tor_gettimeofday(&now);
  49. t = (time_t)now.tv_sec;
  50. n = strftime(buf, buf_len, "%b %d %H:%M:%S", localtime(&t));
  51. n += snprintf(buf+n, buf_len-n,
  52. ".%.3ld [%s] ",
  53. (long)now.tv_usec / 1000, sev_to_string(severity));
  54. if(n > buf_len)
  55. n = buf_len-1; /* the *nprintf funcs return how many bytes they
  56. * _would_ print, if the output is truncated.
  57. * Subtract one because the count doesn't include the \0 */
  58. return n;
  59. }
  60. /** If lf refers to an actual file that we have just opened, and the file
  61. * contains no data, log an "opening new logfile" message at the top. **/
  62. static void log_tor_version(logfile_t *lf)
  63. {
  64. char buf[256];
  65. size_t n;
  66. if (!lf->needs_close)
  67. /* If it doesn't get closed, it isn't really a file. */
  68. return;
  69. if (lf->is_temporary)
  70. /* If it's temporary, it isn't really a file. */
  71. return;
  72. if (ftell(lf->file) != 0)
  73. /* We aren't at the start of the file; no need to log. */
  74. return;
  75. n = _log_prefix(buf, 250, LOG_NOTICE);
  76. n += snprintf(buf+n, 250-n, "Tor %s creating new log file\n", VERSION);
  77. if (n>250)
  78. n = 250;
  79. buf[n+1]='\0';
  80. fputs(buf, lf->file);
  81. }
  82. /** Helper: Format a log message into a fixed-sized buffer. (This is
  83. * factored out of <b>logv</b> so that we never format a message more
  84. * than once.)
  85. */
  86. static INLINE void format_msg(char *buf, size_t buf_len,
  87. int severity, const char *funcname,
  88. const char *format, va_list ap)
  89. {
  90. size_t n;
  91. buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
  92. n = _log_prefix(buf, buf_len, severity);
  93. if (funcname) {
  94. n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
  95. if(n > buf_len)
  96. n = buf_len-1;
  97. }
  98. n += vsnprintf(buf+n,buf_len-n,format,ap);
  99. if(n > buf_len)
  100. n = buf_len-1;
  101. buf[n]='\n';
  102. buf[n+1]='\0';
  103. }
  104. /** Helper: sends a message to the appropriate logfiles, at loglevel
  105. * <b>severity</b>. If provided, <b>funcname</b> is prepended to the
  106. * message. The actual message is derived as from vsprintf(format,ap).
  107. */
  108. static void
  109. logv(int severity, const char *funcname, const char *format, va_list ap)
  110. {
  111. char buf[10024];
  112. int formatted = 0;
  113. logfile_t *lf;
  114. assert(format);
  115. for (lf = logfiles; lf; lf = lf->next) {
  116. if (severity < lf->loglevel || severity > lf->max_loglevel)
  117. continue;
  118. if (!lf->file)
  119. continue;
  120. if (!formatted) {
  121. format_msg(buf, 10024, severity, funcname, format, ap);
  122. formatted = 1;
  123. }
  124. if(fputs(buf, lf->file) == EOF) { /* error */
  125. assert(0); /* XXX */
  126. }
  127. if(fflush(lf->file) == EOF) { /* error */
  128. /* don't log the error! */
  129. assert(0); /* XXX fail for now. what's better to do? */
  130. }
  131. }
  132. }
  133. /** Output a message to the log. */
  134. void _log(int severity, const char *format, ...)
  135. {
  136. va_list ap;
  137. va_start(ap,format);
  138. logv(severity, NULL, format, ap);
  139. va_end(ap);
  140. }
  141. /** Output a message to the log, prefixed with a function name <b>fn</b>. */
  142. void _log_fn(int severity, const char *fn, const char *format, ...)
  143. {
  144. va_list ap;
  145. va_start(ap,format);
  146. logv(severity, fn, format, ap);
  147. va_end(ap);
  148. }
  149. /** Close all open log files. */
  150. void close_logs()
  151. {
  152. logfile_t *victim;
  153. while(logfiles) {
  154. victim = logfiles;
  155. logfiles = logfiles->next;
  156. if (victim->needs_close)
  157. fclose(victim->file);
  158. tor_free(victim->filename);
  159. tor_free(victim);
  160. }
  161. }
  162. /** Close and re-open all log files; used to rotate logs on SIGHUP. */
  163. void reset_logs()
  164. {
  165. logfile_t *lf;
  166. for (lf = logfiles; lf; lf = lf->next) {
  167. if (lf->needs_close) {
  168. fclose(lf->file);
  169. lf->file = fopen(lf->filename, "a");
  170. log_tor_version(lf);
  171. }
  172. }
  173. }
  174. /** Add a log handler to send all messages of severity <b>loglevel</b>
  175. * or higher to <b>stream</b>. */
  176. void add_stream_log(int loglevelMin, int loglevelMax, const char *name, FILE *stream)
  177. {
  178. logfile_t *lf;
  179. lf = tor_malloc(sizeof(logfile_t));
  180. lf->filename = tor_strdup(name);
  181. lf->needs_close = 0;
  182. lf->loglevel = loglevelMin;
  183. lf->max_loglevel = loglevelMax;
  184. lf->file = stream;
  185. lf->next = logfiles;
  186. lf->is_temporary = 0;
  187. logfiles = lf;
  188. }
  189. /** Add a log handler to receive messages during startup (before the real
  190. * logs are initialized).
  191. */
  192. void add_temp_log(void)
  193. {
  194. add_stream_log(LOG_INFO, LOG_ERR, "<temp>", stdout);
  195. logfiles->is_temporary = 1;
  196. }
  197. void close_temp_logs(void)
  198. {
  199. logfile_t *lf, **p;
  200. for (p = &logfiles; *p; ) {
  201. if ((*p)->is_temporary) {
  202. lf = *p;
  203. *p = (*p)->next;
  204. if (lf->needs_close)
  205. fclose(lf->file);
  206. tor_free(lf->filename);
  207. tor_free(lf);
  208. } else {
  209. p = &((*p)->next);
  210. }
  211. }
  212. }
  213. void mark_logs_temp(void)
  214. {
  215. logfile_t *lf;
  216. for (lf = logfiles; lf; lf = lf->next)
  217. lf->is_temporary = 1;
  218. }
  219. /**
  220. * Add a log handler to send messages to <b>filename</b>. If opening
  221. * the logfile fails, -1 is returned and errno is set appropriately
  222. * (by fopen).
  223. */
  224. int add_file_log(int loglevelMin, int loglevelMax, const char *filename)
  225. {
  226. FILE *f;
  227. f = fopen(filename, "a");
  228. if (!f) return -1;
  229. add_stream_log(loglevelMin, loglevelMax, filename, f);
  230. logfiles->needs_close = 1;
  231. log_tor_version(logfiles);
  232. return 0;
  233. }
  234. /** If <b>level</b> is a valid log severity, return the corresponding
  235. * numeric value. Otherwise, return -1. */
  236. int parse_log_level(const char *level) {
  237. if (!strcasecmp(level, "err"))
  238. return LOG_ERR;
  239. if (!strcasecmp(level, "warn"))
  240. return LOG_WARN;
  241. if (!strcasecmp(level, "notice"))
  242. return LOG_NOTICE;
  243. if (!strcasecmp(level, "info"))
  244. return LOG_INFO;
  245. if (!strcasecmp(level, "debug"))
  246. return LOG_DEBUG;
  247. return -1;
  248. }
  249. int get_min_log_level(void)
  250. {
  251. logfile_t *lf;
  252. int min = LOG_ERR;
  253. for (lf = logfiles; lf; lf = lf->next) {
  254. if (lf->loglevel < min)
  255. min = lf->loglevel;
  256. }
  257. return min;
  258. }
  259. /*
  260. Local Variables:
  261. mode:c
  262. indent-tabs-mode:nil
  263. c-basic-offset:2
  264. End:
  265. */