log.c 7.5 KB

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