log.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. #define TRUNCATED_STR "[...truncated]"
  21. #define TRUNCATED_STR_LEN 14
  22. /** Information for a single logfile; only used in log.c */
  23. typedef struct logfile_t {
  24. struct logfile_t *next; /**< Next logfile_t in the linked list. */
  25. char *filename; /**< Filename to open. */
  26. FILE *file; /**< Stream to receive log messages. */
  27. int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
  28. int loglevel; /**< Lowest severity level to send to this stream. */
  29. int max_loglevel; /**< Highest severity level to send to this stream. */
  30. int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
  31. } logfile_t;
  32. /** Helper: map a log severity to descriptive string. */
  33. static INLINE const char *sev_to_string(int severity) {
  34. switch(severity) {
  35. case LOG_DEBUG: return "debug";
  36. case LOG_INFO: return "info";
  37. case LOG_NOTICE: return "notice";
  38. case LOG_WARN: return "warn";
  39. case LOG_ERR: return "err";
  40. default: assert(0); return "UNKNOWN";
  41. }
  42. }
  43. /** Linked list of logfile_t. */
  44. static logfile_t *logfiles = NULL;
  45. static void delete_log(logfile_t *victim);
  46. static INLINE size_t
  47. _log_prefix(char *buf, size_t buf_len, int severity)
  48. {
  49. time_t t;
  50. struct timeval now;
  51. size_t n;
  52. tor_gettimeofday(&now);
  53. t = (time_t)now.tv_sec;
  54. n = strftime(buf, buf_len, "%b %d %H:%M:%S", localtime(&t));
  55. n += snprintf(buf+n, buf_len-n,
  56. ".%.3ld [%s] ",
  57. (long)now.tv_usec / 1000, sev_to_string(severity));
  58. if(n > buf_len)
  59. n = buf_len-1; /* the *nprintf funcs return how many bytes they
  60. * _would_ print, if the output is truncated.
  61. * Subtract one because the count doesn't include the \0 */
  62. return n;
  63. }
  64. /** If lf refers to an actual file that we have just opened, and the file
  65. * contains no data, log an "opening new logfile" message at the top. **/
  66. static void log_tor_version(logfile_t *lf, int reset)
  67. {
  68. char buf[256];
  69. size_t n;
  70. int is_new;
  71. if (!lf->needs_close)
  72. /* If it doesn't get closed, it isn't really a file. */
  73. return;
  74. if (lf->is_temporary)
  75. /* If it's temporary, it isn't really a file. */
  76. return;
  77. is_new = (ftell(lf->file) == 0);
  78. if (reset && !is_new)
  79. /* We are resetting, but we aren't at the start of the file; no
  80. * need to log again. */
  81. return;
  82. n = _log_prefix(buf, 250, LOG_NOTICE);
  83. n += snprintf(buf+n, 250-n, "Tor %s opening %slog file.\n", VERSION,
  84. is_new?"new ":"");
  85. if (n>250)
  86. n = 250;
  87. buf[n+1]='\0';
  88. fputs(buf, lf->file);
  89. }
  90. /** Helper: Format a log message into a fixed-sized buffer. (This is
  91. * factored out of <b>logv</b> so that we never format a message more
  92. * than once.)
  93. */
  94. static INLINE void format_msg(char *buf, size_t buf_len,
  95. int severity, const char *funcname,
  96. const char *format, va_list ap)
  97. {
  98. size_t n;
  99. buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
  100. n = _log_prefix(buf, buf_len, severity);
  101. if (funcname) {
  102. n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
  103. if(n > buf_len)
  104. n = buf_len-1;
  105. }
  106. n += vsnprintf(buf+n,buf_len-n,format,ap);
  107. if(n > buf_len) {
  108. n = buf_len-1;
  109. strcpy(buf+n-TRUNCATED_STR_LEN, TRUNCATED_STR);
  110. }
  111. buf[n]='\n';
  112. buf[n+1]='\0';
  113. }
  114. /** Helper: sends a message to the appropriate logfiles, at loglevel
  115. * <b>severity</b>. If provided, <b>funcname</b> is prepended to the
  116. * message. The actual message is derived as from vsprintf(format,ap).
  117. */
  118. static void
  119. logv(int severity, const char *funcname, const char *format, va_list ap)
  120. {
  121. char buf[10024];
  122. int formatted = 0;
  123. logfile_t *lf;
  124. assert(format);
  125. lf = logfiles;
  126. while(lf) {
  127. if (severity < lf->loglevel || severity > lf->max_loglevel) {
  128. lf = lf->next;
  129. continue;
  130. }
  131. if (!lf->file) {
  132. lf = lf->next;
  133. continue;
  134. }
  135. if (!formatted) {
  136. format_msg(buf, sizeof(buf), severity, funcname, format, ap);
  137. formatted = 1;
  138. }
  139. if(fputs(buf, lf->file) == EOF ||
  140. fflush(lf->file) == EOF) { /* error */
  141. /* don't log the error! Blow away this log entry and continue. */
  142. logfile_t *victim = lf;
  143. lf = victim->next;
  144. delete_log(victim);
  145. } else {
  146. lf = lf->next;
  147. }
  148. }
  149. }
  150. /** Output a message to the log. */
  151. void _log(int severity, const char *format, ...)
  152. {
  153. va_list ap;
  154. va_start(ap,format);
  155. logv(severity, NULL, format, ap);
  156. va_end(ap);
  157. }
  158. /** Output a message to the log, prefixed with a function name <b>fn</b>. */
  159. void _log_fn(int severity, const char *fn, const char *format, ...)
  160. {
  161. va_list ap;
  162. va_start(ap,format);
  163. logv(severity, fn, format, ap);
  164. va_end(ap);
  165. }
  166. /** Close all open log files. */
  167. void close_logs()
  168. {
  169. logfile_t *victim;
  170. while(logfiles) {
  171. victim = logfiles;
  172. logfiles = logfiles->next;
  173. if (victim->needs_close)
  174. fclose(victim->file);
  175. tor_free(victim->filename);
  176. tor_free(victim);
  177. }
  178. }
  179. /** Close and re-open all log files; used to rotate logs on SIGHUP. */
  180. void reset_logs()
  181. {
  182. logfile_t *lf = logfiles;
  183. while(lf) {
  184. if (lf->needs_close) {
  185. if(fclose(lf->file)==EOF ||
  186. !(lf->file = fopen(lf->filename, "a"))) {
  187. /* error. don't log it. delete the log entry and continue. */
  188. logfile_t *victim = lf;
  189. lf = victim->next;
  190. delete_log(victim);
  191. continue;
  192. } else {
  193. log_tor_version(lf, 1);
  194. }
  195. }
  196. lf = lf->next;
  197. }
  198. }
  199. /** Remove and free the log entry <b>victim</b> from the linked-list
  200. * logfiles (it must be present in the list when this function is
  201. * called). After this function is called, the caller shouldn't refer
  202. * to <b>victim</b> anymore.
  203. */
  204. static void delete_log(logfile_t *victim) {
  205. logfile_t *tmpl;
  206. if(victim == logfiles)
  207. logfiles = victim->next;
  208. else {
  209. for(tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ;
  210. tor_assert(tmpl && tmpl->next == victim);
  211. tmpl->next = victim->next;
  212. }
  213. tor_free(victim->filename);
  214. tor_free(victim);
  215. }
  216. /** Add a log handler to send all messages of severity <b>loglevel</b>
  217. * or higher to <b>stream</b>. */
  218. void add_stream_log(int loglevelMin, int loglevelMax, const char *name, FILE *stream)
  219. {
  220. logfile_t *lf;
  221. lf = tor_malloc(sizeof(logfile_t));
  222. lf->filename = tor_strdup(name);
  223. lf->needs_close = 0;
  224. lf->loglevel = loglevelMin;
  225. lf->max_loglevel = loglevelMax;
  226. lf->file = stream;
  227. lf->next = logfiles;
  228. lf->is_temporary = 0;
  229. logfiles = lf;
  230. }
  231. /** Add a log handler to receive messages during startup (before the real
  232. * logs are initialized).
  233. */
  234. void add_temp_log(void)
  235. {
  236. add_stream_log(LOG_INFO, LOG_ERR, "<temp>", stdout);
  237. logfiles->is_temporary = 1;
  238. }
  239. void close_temp_logs(void)
  240. {
  241. logfile_t *lf, **p;
  242. for (p = &logfiles; *p; ) {
  243. if ((*p)->is_temporary) {
  244. lf = *p;
  245. *p = (*p)->next;
  246. if (lf->needs_close)
  247. fclose(lf->file);
  248. tor_free(lf->filename);
  249. tor_free(lf);
  250. } else {
  251. p = &((*p)->next);
  252. }
  253. }
  254. }
  255. void mark_logs_temp(void)
  256. {
  257. logfile_t *lf;
  258. for (lf = logfiles; lf; lf = lf->next)
  259. lf->is_temporary = 1;
  260. }
  261. /**
  262. * Add a log handler to send messages to <b>filename</b>. If opening
  263. * the logfile fails, -1 is returned and errno is set appropriately
  264. * (by fopen).
  265. */
  266. int add_file_log(int loglevelMin, int loglevelMax, const char *filename)
  267. {
  268. FILE *f;
  269. f = fopen(filename, "a");
  270. if (!f) return -1;
  271. add_stream_log(loglevelMin, loglevelMax, filename, f);
  272. logfiles->needs_close = 1;
  273. log_tor_version(logfiles, 0);
  274. return 0;
  275. }
  276. /** If <b>level</b> is a valid log severity, return the corresponding
  277. * numeric value. Otherwise, return -1. */
  278. int parse_log_level(const char *level) {
  279. if (!strcasecmp(level, "err"))
  280. return LOG_ERR;
  281. if (!strcasecmp(level, "warn"))
  282. return LOG_WARN;
  283. if (!strcasecmp(level, "notice"))
  284. return LOG_NOTICE;
  285. if (!strcasecmp(level, "info"))
  286. return LOG_INFO;
  287. if (!strcasecmp(level, "debug"))
  288. return LOG_DEBUG;
  289. return -1;
  290. }
  291. int get_min_log_level(void)
  292. {
  293. logfile_t *lf;
  294. int min = LOG_ERR;
  295. for (lf = logfiles; lf; lf = lf->next) {
  296. if (lf->loglevel < min)
  297. min = lf->loglevel;
  298. }
  299. return min;
  300. }
  301. /*
  302. Local Variables:
  303. mode:c
  304. indent-tabs-mode:nil
  305. c-basic-offset:2
  306. End:
  307. */