debug.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:10k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: debug.c,v 1.74 1999/01/11 21:55:38 wessels Exp $
  3.  *
  4.  * DEBUG: section 0     Debug Routines
  5.  * AUTHOR: Harvest Derived
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. static char *debug_log_file = NULL;
  36. static int Ctx_Lock = 0;
  37. static const char *debugLogTime(time_t);
  38. static void ctx_print();
  39. #if STDC_HEADERS
  40. void
  41. _db_print(const char *format,...)
  42. {
  43. #if defined(__QNX__)
  44.     va_list eargs;
  45. #endif
  46.     va_list args;
  47. #else
  48. void
  49. _db_print(va_alist)
  50.      va_dcl
  51. {
  52.     va_list args;
  53.     const char *format = NULL;
  54. #endif
  55.     LOCAL_ARRAY(char, f, BUFSIZ);
  56. #if HAVE_SYSLOG
  57.     LOCAL_ARRAY(char, tmpbuf, BUFSIZ);
  58. #endif
  59. #if STDC_HEADERS
  60.     va_start(args, format);
  61. #if defined(__QNX__)
  62.     va_start(eargs, format);
  63. #endif
  64. #else
  65.     va_start(args);
  66.     format = va_arg(args, const char *);
  67. #endif
  68.     if (debug_log == NULL)
  69. return;
  70.     /* give a chance to context-based debugging to print current context */
  71.     if (!Ctx_Lock)
  72. ctx_print();
  73.     snprintf(f, BUFSIZ, "%s| %s",
  74. debugLogTime(squid_curtime),
  75. format);
  76. #if HAVE_SYSLOG
  77.     /* level 0,1 go to syslog */
  78.     if (_db_level <= 1 && opt_syslog_enable) {
  79. tmpbuf[0] = '';
  80. vsnprintf(tmpbuf, BUFSIZ, format, args);
  81. tmpbuf[BUFSIZ - 1] = '';
  82. syslog(_db_level == 0 ? LOG_WARNING : LOG_NOTICE, "%s", tmpbuf);
  83.     }
  84. #endif /* HAVE_SYSLOG */
  85.     /* write to log file */
  86. #if defined(__QNX__)
  87.     vfprintf(debug_log, f, eargs);
  88. #else
  89.     vfprintf(debug_log, f, args);
  90. #endif
  91.     if (!Config.onoff.buffered_logs)
  92. fflush(debug_log);
  93.     if (opt_debug_stderr >= _db_level && debug_log != stderr) {
  94. #if defined(__QNX__)
  95. vfprintf(stderr, f, eargs);
  96. #else
  97. vfprintf(stderr, f, args);
  98. #endif
  99.     }
  100. #if defined(__QNX__)
  101.     va_end(eargs);
  102. #endif
  103.     va_end(args);
  104. }
  105. static void
  106. debugArg(const char *arg)
  107. {
  108.     int s = 0;
  109.     int l = 0;
  110.     int i;
  111.     if (!strncasecmp(arg, "ALL", 3)) {
  112. s = -1;
  113. arg += 4;
  114.     } else {
  115. s = atoi(arg);
  116. while (*arg && *arg++ != ',');
  117.     }
  118.     l = atoi(arg);
  119.     if (s >= 0) {
  120. debugLevels[s] = l;
  121. return;
  122.     }
  123.     for (i = 0; i < MAX_DEBUG_SECTIONS; i++)
  124. debugLevels[i] = l;
  125. }
  126. static void
  127. debugOpenLog(const char *logfile)
  128. {
  129.     if (logfile == NULL) {
  130. debug_log = stderr;
  131. return;
  132.     }
  133.     if (debug_log_file)
  134. xfree(debug_log_file);
  135.     debug_log_file = xstrdup(logfile); /* keep a static copy */
  136.     if (debug_log && debug_log != stderr)
  137. fclose(debug_log);
  138.     debug_log = fopen(logfile, "a+");
  139.     if (!debug_log) {
  140. fprintf(stderr, "WARNING: Cannot write log file: %sn", logfile);
  141. perror(logfile);
  142. fprintf(stderr, "         messages will be sent to 'stderr'.n");
  143. fflush(stderr);
  144. debug_log = stderr;
  145.     }
  146. }
  147. void
  148. _db_init(const char *logfile, const char *options)
  149. {
  150.     int i;
  151.     char *p = NULL;
  152.     char *s = NULL;
  153.     for (i = 0; i < MAX_DEBUG_SECTIONS; i++)
  154. debugLevels[i] = -1;
  155.     if (options) {
  156. p = xstrdup(options);
  157. for (s = strtok(p, w_space); s; s = strtok(NULL, w_space))
  158.     debugArg(s);
  159. xfree(p);
  160.     }
  161.     debugOpenLog(logfile);
  162. #if HAVE_SYSLOG && defined(LOG_LOCAL4)
  163.     if (opt_syslog_enable)
  164. openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
  165. #endif /* HAVE_SYSLOG */
  166. }
  167. void
  168. _db_rotate_log(void)
  169. {
  170.     int i;
  171.     LOCAL_ARRAY(char, from, MAXPATHLEN);
  172.     LOCAL_ARRAY(char, to, MAXPATHLEN);
  173. #ifdef S_ISREG
  174.     struct stat sb;
  175. #endif
  176.     if (debug_log_file == NULL)
  177. return;
  178. #ifdef S_ISREG
  179.     if (stat(debug_log_file, &sb) == 0)
  180. if (S_ISREG(sb.st_mode) == 0)
  181.     return;
  182. #endif
  183.     /* Rotate numbers 0 through N up one */
  184.     for (i = Config.Log.rotateNumber; i > 1;) {
  185. i--;
  186. snprintf(from, MAXPATHLEN, "%s.%d", debug_log_file, i - 1);
  187. snprintf(to, MAXPATHLEN, "%s.%d", debug_log_file, i);
  188. rename(from, to);
  189.     }
  190.     /* Rotate the current log to .0 */
  191.     if (Config.Log.rotateNumber > 0) {
  192. snprintf(to, MAXPATHLEN, "%s.%d", debug_log_file, 0);
  193. rename(debug_log_file, to);
  194.     }
  195.     /* Close and reopen the log.  It may have been renamed "manually"
  196.      * before HUP'ing us. */
  197.     if (debug_log != stderr)
  198. debugOpenLog(Config.Log.log);
  199. }
  200. static const char *
  201. debugLogTime(time_t t)
  202. {
  203.     struct tm *tm;
  204.     static char buf[128];
  205.     static time_t last_t = 0;
  206.     if (t != last_t) {
  207. tm = localtime(&t);
  208. strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
  209. last_t = t;
  210.     }
  211.     return buf;
  212. }
  213. void
  214. xassert(const char *msg, const char *file, int line)
  215. {
  216.     debug(0, 0) ("assertion failed: %s:%d: "%s"n", file, line, msg);
  217.     if (!shutting_down)
  218. abort();
  219. }
  220. /*
  221.  * Context-based Debugging
  222.  *
  223.  * Rationale
  224.  * ---------
  225.  * 
  226.  * When you have a long nested processing sequence, it is often impossible
  227.  * for low level routines to know in what larger context they operate. If a
  228.  * routine coredumps, one can restore the context using debugger trace.
  229.  * However, in many case you do not want to coredump, but just want to report
  230.  * a potential problem. A report maybe useless out of problem context.
  231.  * 
  232.  * To solve this potential problem, use the following approach:
  233.  * 
  234.  * int
  235.  * top_level_foo(const char *url)
  236.  * {
  237.  *      // define current context
  238.  *      // note: we stack but do not dup ctx descriptions!
  239.  *      Ctx ctx = ctx_enter(url);
  240.  *      ...
  241.  *      // go down; middle_level_bar will eventually call bottom_level_boo
  242.  *      middle_level_bar(method, protocol);
  243.  *      ...
  244.  *      // exit, clean after yourself
  245.  *      ctx_exit(ctx);
  246.  * }
  247.  * 
  248.  * void
  249.  * bottom_level_boo(int status, void *data)
  250.  * {
  251.  *      // detect exceptional condition, and simply report it, the context
  252.  *      // information will be available somewhere close in the log file
  253.  *      if (status == STRANGE_STATUS)
  254.  *      debug(13, 6) ("DOS attack detected, data: %pn", data);
  255.  *      ...
  256.  * }
  257.  * 
  258.  * Current implementation is extremely simple but still very handy. It has a
  259.  * negligible overhead (descriptions are not duplicated).
  260.  * 
  261.  * When the _first_ debug message for a given context is printed, it is
  262.  * prepended with the current context description. Context is printed with
  263.  * the same debugging level as the original message.
  264.  * 
  265.  * Note that we do not print context every type you do ctx_enter(). This
  266.  * approach would produce too many useless messages.  For the same reason, a
  267.  * context description is printed at most _once_ even if you have 10
  268.  * debugging messages within one context.
  269.  * 
  270.  * Contexts can be nested, of course. You must use ctx_enter() to enter a
  271.  * context (push it onto stack).  It is probably safe to exit several nested
  272.  * contexts at _once_ by calling ctx_exit() at the top level (this will pop
  273.  * all context till current one). However, as in any stack, you cannot start
  274.  * in the middle.
  275.  * 
  276.  * Analysis: 
  277.  * i)   locate debugging message,
  278.  * ii)  locate current context by going _upstream_ in your log file,
  279.  * iii) hack away.
  280.  *
  281.  *
  282.  * To-Do: 
  283.  * -----
  284.  *
  285.  *       decide if we want to dup() descriptions (adds overhead) but allows to
  286.  *       add printf()-style interface
  287.  *
  288.  * implementation:
  289.  * ---------------
  290.  *
  291.  * descriptions for contexts over CTX_MAX_LEVEL limit are ignored, you probably
  292.  * have a bug if your nesting goes that deep.
  293.  */
  294. #define CTX_MAX_LEVEL 255
  295. /*
  296.  * produce a warning when nesting reaches this level and then double
  297.  * the level
  298.  */
  299. static int Ctx_Warn_Level = 32;
  300. /* all descriptions has been printed up to this level */
  301. static int Ctx_Reported_Level = -1;
  302. /* descriptions are still valid or active up to this level */
  303. static int Ctx_Valid_Level = -1;
  304. /* current level, the number of nested ctx_enter() calls */
  305. static int Ctx_Current_Level = -1;
  306. /* saved descriptions (stack) */
  307. static const char *Ctx_Descrs[CTX_MAX_LEVEL + 1];
  308. /* "safe" get secription */
  309. static const char *ctx_get_descr(Ctx ctx);
  310. Ctx
  311. ctx_enter(const char *descr)
  312. {
  313.     Ctx_Current_Level++;
  314.     if (Ctx_Current_Level <= CTX_MAX_LEVEL)
  315. Ctx_Descrs[Ctx_Current_Level] = descr;
  316.     if (Ctx_Current_Level == Ctx_Warn_Level) {
  317. debug(0, 0) ("# ctx: suspiciously deep (%d) nesting:n", Ctx_Warn_Level);
  318. Ctx_Warn_Level *= 2;
  319.     }
  320.     return Ctx_Current_Level;
  321. }
  322. void
  323. ctx_exit(Ctx ctx)
  324. {
  325.     assert(ctx >= 0);
  326.     Ctx_Current_Level = (ctx >= 0) ? ctx - 1 : -1;
  327.     if (Ctx_Valid_Level > Ctx_Current_Level)
  328. Ctx_Valid_Level = Ctx_Current_Level;
  329. }
  330. /*
  331.  * the idea id to print each context description at most once but provide enough
  332.  * info for deducing the current execution stack
  333.  */
  334. static void
  335. ctx_print()
  336. {
  337.     /* lock so _db_print will not call us recursively */
  338.     Ctx_Lock++;
  339.     /* ok, user saw [0,Ctx_Reported_Level] descriptions */
  340.     /* first inform about entries popped since user saw them */
  341.     if (Ctx_Valid_Level < Ctx_Reported_Level) {
  342. if (Ctx_Reported_Level != Ctx_Valid_Level + 1)
  343.     _db_print("ctx: exit levels from %2d down to %2dn",
  344. Ctx_Reported_Level, Ctx_Valid_Level + 1);
  345. else
  346.     _db_print("ctx: exit level %2dn", Ctx_Reported_Level);
  347. Ctx_Reported_Level = Ctx_Valid_Level;
  348.     }
  349.     /* report new contexts that were pushed since last report */
  350.     while (Ctx_Reported_Level < Ctx_Current_Level) {
  351. Ctx_Reported_Level++;
  352. Ctx_Valid_Level++;
  353. _db_print("ctx: enter level %2d: '%s'n", Ctx_Reported_Level,
  354.     ctx_get_descr(Ctx_Reported_Level));
  355.     }
  356.     /* unlock */
  357.     Ctx_Lock--;
  358. }
  359. /* checks for nulls and overflows */
  360. static const char *
  361. ctx_get_descr(Ctx ctx)
  362. {
  363.     if (ctx < 0 || ctx > CTX_MAX_LEVEL)
  364. return "<lost>";
  365.     return Ctx_Descrs[ctx] ? Ctx_Descrs[ctx] : "<null>";
  366. }