debug.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 00 Debug Routines */
10 
11 #include "squid.h"
12 #include "Debug.h"
13 #include "ipc/Kids.h"
14 #include "SquidTime.h"
15 #include "util.h"
16 
17 #include <algorithm>
18 
19 /* for shutting_down flag in xassert() */
20 #include "globals.h"
21 
23 int Debug::override_X = 0;
24 int Debug::log_stderr = -1;
25 bool Debug::log_syslog = false;
27 char *Debug::cache_log = NULL;
28 int Debug::rotateNumber = -1;
29 static int Ctx_Lock = 0;
30 static const char *debugLogTime(void);
31 static const char *debugLogKid(void);
32 static void ctx_print(void);
33 #if HAVE_SYSLOG
34 #ifdef LOG_LOCAL4
35 static int syslog_facility = 0;
36 #endif
37 static void _db_print_syslog(const bool forceAlert, const char *format, va_list args);
38 #endif
39 static void _db_print_stderr(const char *format, va_list args);
40 static void _db_print_file(const char *format, va_list args);
41 
42 #if _SQUID_WINDOWS_
43 extern LPCRITICAL_SECTION dbg_mutex;
44 typedef BOOL (WINAPI * PFInitializeCriticalSectionAndSpinCount) (LPCRITICAL_SECTION, DWORD);
45 #endif
46 
48 class DebugFile
49 {
50 public:
51  DebugFile() {}
52  ~DebugFile() { clear(); }
53  DebugFile(DebugFile &&) = delete; // no copying or moving of any kind
54 
56  void reset(FILE *newFile, const char *newName);
57 
59  void clear() { reset(nullptr, nullptr); }
60 
62  FILE *file() { return file_ ? file_ : stderr; }
63 
64  char *name = nullptr;
65 
66 private:
67  friend void ResyncDebugLog(FILE *newFile);
68 
69  FILE *file_ = nullptr;
70 };
71 
75 
76 FILE *
78  return TheLog.file();
79 }
80 
81 void
83 {
84  TheLog.clear();
85 }
86 
87 void
88 ResyncDebugLog(FILE *newFile)
89 {
90  TheLog.file_ = newFile;
91 }
92 
93 void
94 DebugFile::reset(FILE *newFile, const char *newName)
95 {
96  // callers must use nullptr instead of the used-as-the-last-resort stderr
97  assert(newFile != stderr || !stderr);
98 
99  if (file_)
100  fclose(file_);
101  file_ = newFile; // may be nil
102 
103  xfree(name);
104  name = newName ? xstrdup(newName) : nullptr;
105 
106  // all open files must have a name
107  // all cleared files must not have a name
108  assert(!file_ == !name);
109 }
110 
111 static
112 void
113 _db_print(const bool forceAlert, const char *format,...)
114 {
115  char f[BUFSIZ];
116  f[0]='\0';
117  va_list args1;
118  va_list args2;
119  va_list args3;
120 
121 #if _SQUID_WINDOWS_
122  /* Multiple WIN32 threads may call this simultaneously */
123 
124  if (!dbg_mutex) {
125  HMODULE krnl_lib = GetModuleHandle("Kernel32");
126  PFInitializeCriticalSectionAndSpinCount InitializeCriticalSectionAndSpinCount = NULL;
127 
128  if (krnl_lib)
129  InitializeCriticalSectionAndSpinCount =
130  (PFInitializeCriticalSectionAndSpinCount) GetProcAddress(krnl_lib,
131  "InitializeCriticalSectionAndSpinCount");
132 
133  dbg_mutex = static_cast<CRITICAL_SECTION*>(xcalloc(1, sizeof(CRITICAL_SECTION)));
134 
135  if (InitializeCriticalSectionAndSpinCount) {
136  /* let multiprocessor systems EnterCriticalSection() fast */
137 
138  if (!InitializeCriticalSectionAndSpinCount(dbg_mutex, 4000)) {
139  if (debug_log) {
140  fprintf(debug_log, "FATAL: _db_print: can't initialize critical section\n");
141  fflush(debug_log);
142  }
143 
144  fprintf(stderr, "FATAL: _db_print: can't initialize critical section\n");
145  abort();
146  } else
147  InitializeCriticalSection(dbg_mutex);
148  }
149  }
150 
151  EnterCriticalSection(dbg_mutex);
152 #endif
153 
154  /* give a chance to context-based debugging to print current context */
155  if (!Ctx_Lock)
156  ctx_print();
157 
158  va_start(args1, format);
159  va_start(args2, format);
160  va_start(args3, format);
161 
162  snprintf(f, BUFSIZ, "%s%s| %s",
163  debugLogTime(),
164  debugLogKid(),
165  format);
166 
167  _db_print_file(f, args1);
168  _db_print_stderr(f, args2);
169 
170 #if HAVE_SYSLOG
171  _db_print_syslog(forceAlert, format, args3);
172 #endif
173 
174 #if _SQUID_WINDOWS_
175  LeaveCriticalSection(dbg_mutex);
176 #endif
177 
178  va_end(args1);
179  va_end(args2);
180  va_end(args3);
181 }
182 
183 static void
184 _db_print_file(const char *format, va_list args)
185 {
186  if (debug_log == NULL)
187  return;
188 
189  /* give a chance to context-based debugging to print current context */
190  if (!Ctx_Lock)
191  ctx_print();
192 
193  vfprintf(debug_log, format, args);
194  fflush(debug_log);
195 }
196 
197 static void
198 _db_print_stderr(const char *format, va_list args)
199 {
201  return;
202 
203  if (debug_log == stderr)
204  return;
205 
206  vfprintf(stderr, format, args);
207 }
208 
209 #if HAVE_SYSLOG
210 static void
211 _db_print_syslog(const bool forceAlert, const char *format, va_list args)
212 {
213  /* level 0,1 go to syslog */
214 
215  if (!forceAlert) {
216  if (Debug::Level() > 1)
217  return;
218 
219  if (!Debug::log_syslog)
220  return;
221  }
222 
223  char tmpbuf[BUFSIZ];
224  tmpbuf[0] = '\0';
225 
226  vsnprintf(tmpbuf, BUFSIZ, format, args);
227 
228  tmpbuf[BUFSIZ - 1] = '\0';
229 
230  syslog(forceAlert ? LOG_ALERT : (Debug::Level() == 0 ? LOG_WARNING : LOG_NOTICE), "%s", tmpbuf);
231 }
232 #endif /* HAVE_SYSLOG */
233 
234 static void
235 debugArg(const char *arg)
236 {
237  int s = 0;
238  int l = 0;
239  int i;
240 
241  if (!strncasecmp(arg, "rotate=", 7)) {
242  arg += 7;
243  Debug::rotateNumber = atoi(arg);
244  return;
245  } else if (!strncasecmp(arg, "ALL", 3)) {
246  s = -1;
247  arg += 4;
248  } else {
249  s = atoi(arg);
250  while (*arg && *arg++ != ',');
251  }
252 
253  l = atoi(arg);
254  assert(s >= -1);
255 
256  if (s >= MAX_DEBUG_SECTIONS)
257  s = MAX_DEBUG_SECTIONS-1;
258 
259  if (l < 0)
260  l = 0;
261 
262  if (l > 10)
263  l = 10;
264 
265  if (s >= 0) {
266  Debug::Levels[s] = l;
267  return;
268  }
269 
270  for (i = 0; i < MAX_DEBUG_SECTIONS; ++i)
271  Debug::Levels[i] = l;
272 }
273 
274 static void
275 debugOpenLog(const char *logfile)
276 {
277  if (logfile == NULL) {
278  TheLog.clear();
279  return;
280  }
281 
282  // Bug 4423: ignore the stdio: logging module name if present
283  const char *logfilename;
284  if (strncmp(logfile, "stdio:",6) == 0)
285  logfilename = logfile + 6;
286  else
287  logfilename = logfile;
288 
289  if (auto log = fopen(logfilename, "a+")) {
290 #if _SQUID_WINDOWS_
291  setmode(fileno(log), O_TEXT);
292 #endif
293  TheLog.reset(log, logfilename);
294  } else {
295  fprintf(stderr, "WARNING: Cannot write log file: %s\n", logfile);
296  perror(logfile);
297  fprintf(stderr, " messages will be sent to 'stderr'.\n");
298  fflush(stderr);
299  TheLog.clear();
300  }
301 }
302 
303 #if HAVE_SYSLOG
304 #ifdef LOG_LOCAL4
305 
306 static struct syslog_facility_name {
307  const char *name;
308  int facility;
309 }
310 
311 syslog_facility_names[] = {
312 
313 #ifdef LOG_AUTH
314  {
315  "auth", LOG_AUTH
316  },
317 #endif
318 #ifdef LOG_AUTHPRIV
319  {
320  "authpriv", LOG_AUTHPRIV
321  },
322 #endif
323 #ifdef LOG_CRON
324  {
325  "cron", LOG_CRON
326  },
327 #endif
328 #ifdef LOG_DAEMON
329  {
330  "daemon", LOG_DAEMON
331  },
332 #endif
333 #ifdef LOG_FTP
334  {
335  "ftp", LOG_FTP
336  },
337 #endif
338 #ifdef LOG_KERN
339  {
340  "kern", LOG_KERN
341  },
342 #endif
343 #ifdef LOG_LPR
344  {
345  "lpr", LOG_LPR
346  },
347 #endif
348 #ifdef LOG_MAIL
349  {
350  "mail", LOG_MAIL
351  },
352 #endif
353 #ifdef LOG_NEWS
354  {
355  "news", LOG_NEWS
356  },
357 #endif
358 #ifdef LOG_SYSLOG
359  {
360  "syslog", LOG_SYSLOG
361  },
362 #endif
363 #ifdef LOG_USER
364  {
365  "user", LOG_USER
366  },
367 #endif
368 #ifdef LOG_UUCP
369  {
370  "uucp", LOG_UUCP
371  },
372 #endif
373 #ifdef LOG_LOCAL0
374  {
375  "local0", LOG_LOCAL0
376  },
377 #endif
378 #ifdef LOG_LOCAL1
379  {
380  "local1", LOG_LOCAL1
381  },
382 #endif
383 #ifdef LOG_LOCAL2
384  {
385  "local2", LOG_LOCAL2
386  },
387 #endif
388 #ifdef LOG_LOCAL3
389  {
390  "local3", LOG_LOCAL3
391  },
392 #endif
393 #ifdef LOG_LOCAL4
394  {
395  "local4", LOG_LOCAL4
396  },
397 #endif
398 #ifdef LOG_LOCAL5
399  {
400  "local5", LOG_LOCAL5
401  },
402 #endif
403 #ifdef LOG_LOCAL6
404  {
405  "local6", LOG_LOCAL6
406  },
407 #endif
408 #ifdef LOG_LOCAL7
409  {
410  "local7", LOG_LOCAL7
411  },
412 #endif
413  {
414  NULL, 0
415  }
416 };
417 
418 #endif
419 
420 void
421 _db_set_syslog(const char *facility)
422 {
423  Debug::log_syslog = true;
424 
425 #ifdef LOG_LOCAL4
426 #ifdef LOG_DAEMON
427 
428  syslog_facility = LOG_DAEMON;
429 #else
430 
431  syslog_facility = LOG_LOCAL4;
432 #endif /* LOG_DAEMON */
433 
434  if (facility) {
435 
436  struct syslog_facility_name *n;
437 
438  for (n = syslog_facility_names; n->name; ++n) {
439  if (strcmp(n->name, facility) == 0) {
440  syslog_facility = n->facility;
441  return;
442  }
443  }
444 
445  fprintf(stderr, "unknown syslog facility '%s'\n", facility);
446  exit(EXIT_FAILURE);
447  }
448 
449 #else
450  if (facility)
451  fprintf(stderr, "syslog facility type not supported on your system\n");
452 
453 #endif /* LOG_LOCAL4 */
454 }
455 
456 #endif
457 
458 void
459 Debug::parseOptions(char const *options)
460 {
461  int i;
462  char *p = NULL;
463  char *s = NULL;
464 
465  if (override_X) {
466  debugs(0, 9, "command-line -X overrides: " << options);
467  return;
468  }
469 
470  for (i = 0; i < MAX_DEBUG_SECTIONS; ++i)
471  Debug::Levels[i] = 0;
472 
473  if (options) {
474  p = xstrdup(options);
475 
476  for (s = strtok(p, w_space); s; s = strtok(NULL, w_space))
477  debugArg(s);
478 
479  xfree(p);
480  }
481 }
482 
483 void
484 _db_init(const char *logfile, const char *options)
485 {
486  Debug::parseOptions(options);
487 
488  debugOpenLog(logfile);
489 
490 #if HAVE_SYSLOG && defined(LOG_LOCAL4)
491 
492  if (Debug::log_syslog)
493  openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, syslog_facility);
494 
495 #endif /* HAVE_SYSLOG */
496 
497  /* Pre-Init TZ env, see bug #2656 */
498  tzset();
499 }
500 
501 void
503 {
504  if (!TheLog.name)
505  return;
506 
507 #ifdef S_ISREG
508  struct stat sb;
509  if (stat(TheLog.name, &sb) == 0)
510  if (S_ISREG(sb.st_mode) == 0)
511  return;
512 #endif
513 
514  char from[MAXPATHLEN];
515  from[0] = '\0';
516 
517  char to[MAXPATHLEN];
518  to[0] = '\0';
519 
520  /*
521  * NOTE: we cannot use xrename here without having it in a
522  * separate file -- tools.c has too many dependencies to be
523  * used everywhere debug.c is used.
524  */
525  /* Rotate numbers 0 through N up one */
526  for (int i = Debug::rotateNumber; i > 1;) {
527  --i;
528  snprintf(from, MAXPATHLEN, "%s.%d", TheLog.name, i - 1);
529  snprintf(to, MAXPATHLEN, "%s.%d", TheLog.name, i);
530 #if _SQUID_WINDOWS_
531  remove
532  (to);
533 #endif
534  errno = 0;
535  if (rename(from, to) == -1) {
536  const auto saved_errno = errno;
537  debugs(0, DBG_IMPORTANT, "log rotation failed: " << xstrerr(saved_errno));
538  }
539  }
540 
541  /* Rotate the current log to .0 */
542  if (Debug::rotateNumber > 0) {
543  // form file names before we may clear TheLog below
544  snprintf(from, MAXPATHLEN, "%s", TheLog.name);
545  snprintf(to, MAXPATHLEN, "%s.%d", TheLog.name, 0);
546 
547 #if _SQUID_WINDOWS_
548  errno = 0;
549  if (remove(to) == -1) {
550  const auto saved_errno = errno;
551  debugs(0, DBG_IMPORTANT, "removal of log file " << to << " failed: " << xstrerr(saved_errno));
552  }
553  TheLog.clear(); // Windows cannot rename() open files
554 #endif
555  errno = 0;
556  if (rename(from, to) == -1) {
557  const auto saved_errno = errno;
558  debugs(0, DBG_IMPORTANT, "renaming file " << from << " to "
559  << to << "failed: " << xstrerr(saved_errno));
560  }
561  }
562 
563  // Close (if we have not already) and reopen the log because
564  // it may have been renamed "manually" before HUP'ing us.
566 }
567 
568 static const char *
570 {
571 
572  time_t t = getCurrentTime();
573 
574  struct tm *tm;
575  static char buf[128]; // arbitrary size, big enough for the below timestamp strings.
576  static time_t last_t = 0;
577 
578  if (Debug::Level() > 1) {
579  // 4 bytes smaller than buf to ensure .NNN catenation by snprintf()
580  // is safe and works even if strftime() fills its buffer.
581  char buf2[sizeof(buf)-4];
582  tm = localtime(&t);
583  strftime(buf2, sizeof(buf2), "%Y/%m/%d %H:%M:%S", tm);
584  buf2[sizeof(buf2)-1] = '\0';
585  const int sz = snprintf(buf, sizeof(buf), "%s.%03d", buf2, static_cast<int>(current_time.tv_usec / 1000));
586  assert(0 < sz && sz < static_cast<int>(sizeof(buf)));
587  last_t = t;
588  } else if (t != last_t) {
589  tm = localtime(&t);
590  const int sz = strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", tm);
591  assert(0 < sz && sz <= static_cast<int>(sizeof(buf)));
592  last_t = t;
593  }
594 
595  buf[sizeof(buf)-1] = '\0';
596  return buf;
597 }
598 
599 static const char *
601 {
602  if (KidIdentifier != 0) {
603  static char buf[16];
604  if (!*buf) // optimization: fill only once after KidIdentifier is set
605  snprintf(buf, sizeof(buf), " kid%d", KidIdentifier);
606  return buf;
607  }
608 
609  return "";
610 }
611 
612 void
613 xassert(const char *msg, const char *file, int line)
614 {
615  debugs(0, DBG_CRITICAL, "assertion failed: " << file << ":" << line << ": \"" << msg << "\"");
616 
617  if (!shutting_down)
618  abort();
619 }
620 
621 /*
622  * Context-based Debugging
623  *
624  * Rationale
625  * ---------
626  *
627  * When you have a long nested processing sequence, it is often impossible
628  * for low level routines to know in what larger context they operate. If a
629  * routine coredumps, one can restore the context using debugger trace.
630  * However, in many case you do not want to coredump, but just want to report
631  * a potential problem. A report maybe useless out of problem context.
632  *
633  * To solve this potential problem, use the following approach:
634  *
635  * int
636  * top_level_foo(const char *url)
637  * {
638  * // define current context
639  * // note: we stack but do not dup ctx descriptions!
640  * Ctx ctx = ctx_enter(url);
641  * ...
642  * // go down; middle_level_bar will eventually call bottom_level_boo
643  * middle_level_bar(method, protocol);
644  * ...
645  * // exit, clean after yourself
646  * ctx_exit(ctx);
647  * }
648  *
649  * void
650  * bottom_level_boo(int status, void *data)
651  * {
652  * // detect exceptional condition, and simply report it, the context
653  * // information will be available somewhere close in the log file
654  * if (status == STRANGE_STATUS)
655  * debugs(13, 6, "DOS attack detected, data: " << data);
656  * ...
657  * }
658  *
659  * Current implementation is extremely simple but still very handy. It has a
660  * negligible overhead (descriptions are not duplicated).
661  *
662  * When the _first_ debug message for a given context is printed, it is
663  * prepended with the current context description. Context is printed with
664  * the same debugging level as the original message.
665  *
666  * Note that we do not print context every type you do ctx_enter(). This
667  * approach would produce too many useless messages. For the same reason, a
668  * context description is printed at most _once_ even if you have 10
669  * debugging messages within one context.
670  *
671  * Contexts can be nested, of course. You must use ctx_enter() to enter a
672  * context (push it onto stack). It is probably safe to exit several nested
673  * contexts at _once_ by calling ctx_exit() at the top level (this will pop
674  * all context till current one). However, as in any stack, you cannot start
675  * in the middle.
676  *
677  * Analysis:
678  * i) locate debugging message,
679  * ii) locate current context by going _upstream_ in your log file,
680  * iii) hack away.
681  *
682  *
683  * To-Do:
684  * -----
685  *
686  * decide if we want to dup() descriptions (adds overhead) but allows to
687  * add printf()-style interface
688  *
689  * implementation:
690  * ---------------
691  *
692  * descriptions for contexts over CTX_MAX_LEVEL limit are ignored, you probably
693  * have a bug if your nesting goes that deep.
694  */
695 
696 #define CTX_MAX_LEVEL 255
697 
698 /*
699  * produce a warning when nesting reaches this level and then double
700  * the level
701  */
702 static int Ctx_Warn_Level = 32;
703 /* all descriptions has been printed up to this level */
704 static int Ctx_Reported_Level = -1;
705 /* descriptions are still valid or active up to this level */
706 static int Ctx_Valid_Level = -1;
707 /* current level, the number of nested ctx_enter() calls */
708 static int Ctx_Current_Level = -1;
709 /* saved descriptions (stack) */
710 static const char *Ctx_Descrs[CTX_MAX_LEVEL + 1];
711 /* "safe" get secription */
712 static const char *ctx_get_descr(Ctx ctx);
713 
714 Ctx
715 ctx_enter(const char *descr)
716 {
718 
719  if (Ctx_Current_Level <= CTX_MAX_LEVEL)
720  Ctx_Descrs[Ctx_Current_Level] = descr;
721 
722  if (Ctx_Current_Level == Ctx_Warn_Level) {
723  debugs(0, DBG_CRITICAL, "# ctx: suspiciously deep (" << Ctx_Warn_Level << ") nesting:");
724  Ctx_Warn_Level *= 2;
725  }
726 
727  return Ctx_Current_Level;
728 }
729 
730 void
732 {
733  assert(ctx >= 0);
734  Ctx_Current_Level = (ctx >= 0) ? ctx - 1 : -1;
735 
736  if (Ctx_Valid_Level > Ctx_Current_Level)
737  Ctx_Valid_Level = Ctx_Current_Level;
738 }
739 
740 /*
741  * the idea id to print each context description at most once but provide enough
742  * info for deducing the current execution stack
743  */
744 static void
746 {
747  /* lock so _db_print will not call us recursively */
748  ++Ctx_Lock;
749  /* ok, user saw [0,Ctx_Reported_Level] descriptions */
750  /* first inform about entries popped since user saw them */
751 
752  if (Ctx_Valid_Level < Ctx_Reported_Level) {
753  if (Ctx_Reported_Level != Ctx_Valid_Level + 1)
754  _db_print(false, "ctx: exit levels from %2d down to %2d\n",
755  Ctx_Reported_Level, Ctx_Valid_Level + 1);
756  else
757  _db_print(false, "ctx: exit level %2d\n", Ctx_Reported_Level);
758 
759  Ctx_Reported_Level = Ctx_Valid_Level;
760  }
761 
762  /* report new contexts that were pushed since last report */
763  while (Ctx_Reported_Level < Ctx_Current_Level) {
765  ++Ctx_Valid_Level;
766  _db_print(false, "ctx: enter level %2d: '%s'\n", Ctx_Reported_Level,
767  ctx_get_descr(Ctx_Reported_Level));
768  }
769 
770  /* unlock */
771  --Ctx_Lock;
772 }
773 
774 /* checks for nulls and overflows */
775 static const char *
777 {
778  if (ctx < 0 || ctx > CTX_MAX_LEVEL)
779  return "<lost>";
780 
781  return Ctx_Descrs[ctx] ? Ctx_Descrs[ctx] : "<null>";
782 }
783 
784 Debug::Context *Debug::Current = nullptr;
785 
786 Debug::Context::Context(const int aSection, const int aLevel):
787  level(aLevel),
788  sectionLevel(Levels[aSection]),
789  upper(Current),
790  forceAlert(false)
791 {
792  formatStream();
793 }
794 
796 void
797 Debug::Context::rewind(const int aSection, const int aLevel)
798 {
799  level = aLevel;
800  sectionLevel = Levels[aSection];
801  assert(upper == Current);
802 
803  buf.str(std::string());
804  buf.clear();
805  // debugs() users are supposed to preserve format, but
806  // some do not, so we have to waste cycles resetting it for all.
807  formatStream();
808 }
809 
811 void
813 {
814  const static std::ostringstream cleanStream;
815  buf.flags(cleanStream.flags() | std::ios::fixed);
816  buf.width(cleanStream.width());
817  buf.precision(2);
818  buf.fill(' ');
819  // If this is not enough, use copyfmt(cleanStream) which is ~10% slower.
820 }
821 
822 std::ostringstream &
823 Debug::Start(const int section, const int level)
824 {
825  Context *future = nullptr;
826 
827  // prepare future context
828  if (Current) {
829  // all reentrant debugs() calls get here; create a dedicated context
830  future = new Context(section, level);
831  } else {
832  // Optimization: Nearly all debugs() calls get here; avoid allocations
833  static Context *topContext = new Context(1, 1);
834  topContext->rewind(section, level);
835  future = topContext;
836  }
837 
838  Current = future;
839 
840  return future->buf;
841 }
842 
843 void
845 {
846  // TODO: Optimize to remove at least one extra copy.
847  _db_print(Current->forceAlert, "%s\n", Current->buf.str().c_str());
848  Current->forceAlert = false;
849 
850  Context *past = Current;
851  Current = past->upper;
852  if (Current)
853  delete past;
854  // else it was a static topContext from Debug::Start()
855 }
856 
857 void
859 {
860  // the ForceAlert(ostream) manipulator should only be used inside debugs()
861  if (Current)
862  Current->forceAlert = true;
863 }
864 
865 std::ostream&
866 ForceAlert(std::ostream& s)
867 {
869  return s;
870 }
871 
873 void
874 Raw::printHex(std::ostream &os) const
875 {
876  const auto savedFill = os.fill('0');
877  const auto savedFlags = os.flags(); // std::ios_base::fmtflags
878  os << std::hex;
879  std::for_each(data_, data_ + size_,
880  [&os](const char &c) { os << std::setw(2) << static_cast<uint8_t>(c); });
881  os.flags(savedFlags);
882  os.fill(savedFill);
883 }
884 
885 std::ostream &
886 Raw::print(std::ostream &os) const
887 {
888  if (label_)
889  os << ' ' << label_ << '[' << size_ << ']';
890 
891  if (!size_)
892  return os;
893 
894  // finalize debugging level if no level was set explicitly via minLevel()
895  const int finalLevel = (level >= 0) ? level :
896  (size_ > 40 ? DBG_DATA : Debug::SectionLevel());
897  if (finalLevel <= Debug::SectionLevel()) {
898  os << (label_ ? '=' : ' ');
899  if (data_) {
900  if (useHex_)
901  printHex(os);
902  else
903  os.write(data_, size_);
904  } else {
905  os << "[null]";
906  }
907  }
908 
909  return os;
910 }
911 
static void parseOptions(char const *)
Definition: debug.cc:459
static void Finish()
logs output buffer created in Start() and closes debugging context
Definition: debug.cc:844
#define debug_log
change-avoidance macro; new code should call DebugStream() instead
Definition: Debug.h:110
static int rotateNumber
Definition: Debug.h:82
void reset(FILE *newFile, const char *newName)
switches to the new pair, absorbing FILE and duping the name
Definition: debug.cc:94
Context(const int aSectionLevel, const int aLevel)
Definition: debug.cc:786
static const char * debugLogTime(void)
Definition: debug.cc:569
#define assert(EX)
Definition: assert.h:17
static int Ctx_Current_Level
Definition: debug.cc:708
FILE * file_
opened &quot;real&quot; file or nil; never stderr
Definition: debug.cc:69
static int Ctx_Warn_Level
Definition: debug.cc:702
static bool log_syslog
Definition: Debug.h:86
static void _db_print_stderr(const char *format, va_list args)
Definition: debug.cc:198
std::ostream & print(std::ostream &os) const
Definition: debug.cc:886
#define xcalloc
Definition: membanger.c:57
void _db_set_syslog(const char *facility)
Definition: stub_debug.cc:55
static void ForceAlert()
configures the active debugging context to write syslog ALERT
Definition: debug.cc:858
void formatStream()
configures default formatting for the debugging stream
Definition: debug.cc:812
void log(char *format,...)
int i
Definition: membanger.c:49
#define xstrdup
#define MAXPATHLEN
Definition: stdio.h:62
static const char * Ctx_Descrs[CTX_MAX_LEVEL+1]
Definition: debug.cc:710
void ctx_exit(Ctx ctx)
Definition: debug.cc:731
static void _db_print_file(const char *format, va_list args)
Definition: debug.cc:184
static int Level()
minimum level required by the current debugs() call
Definition: Debug.h:91
void _db_rotate_log(void)
Definition: debug.cc:502
#define CTX_MAX_LEVEL
Definition: debug.cc:696
#define DBG_CRITICAL
Definition: Debug.h:45
char * p
Definition: membanger.c:43
std::ostringstream buf
debugs() output sink
Definition: Debug.h:70
struct timeval current_time
Definition: stub_time.cc:15
typedef BOOL(WINAPI *PFChangeServiceConfig2)(SC_HANDLE
#define w_space
friend void ResyncDebugLog(FILE *newFile)
a hack for low-level file descriptor manipulations in ipcCreate()
Definition: debug.cc:88
static int override_X
Definition: Debug.h:84
T & for_each(L const &head, T &visitor)
Definition: Generic.h:23
static int Ctx_Reported_Level
Definition: debug.cc:704
a (FILE*, file name) pair that uses stderr FILE as the last resort
Definition: debug.cc:48
void EVH void * arg
Definition: stub_event.cc:16
void xassert(const char *expr, const char *file, int line)
Definition: assert.cc:11
int shutting_down
Definition: testAddress.cc:36
const char * xstrerr(int error)
Definition: xstrerror.cc:83
meta-information for debugs() or a similar debugging call
Definition: Debug.h:57
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
static int log_stderr
Definition: Debug.h:85
#define DBG_IMPORTANT
Definition: Debug.h:46
static char * debugOptions
Definition: Debug.h:80
DebugFile()
Definition: debug.cc:51
static Context * Current
deepest active context; nil outside debugs()
Definition: Debug.h:103
static char * cache_log
Definition: Debug.h:81
Context * upper
previous or parent record in nested debugging calls
Definition: Debug.h:69
void _db_init(const char *logfile, const char *options)
Definition: debug.cc:484
Ctx ctx_enter(const char *descr)
Definition: debug.cc:715
#define BUFSIZ
Definition: defines.h:20
static void debugOpenLog(const char *logfile)
Definition: debug.cc:275
void const char * buf
Definition: stub_helper.cc:16
#define O_TEXT
Definition: defines.h:201
void StopUsingDebugLog()
start logging to stderr (instead of cache.log, if any)
Definition: debug.cc:82
char * name
Definition: debug.cc:64
static void debugArg(const char *arg)
Definition: debug.cc:235
typedef DWORD
Definition: WinSvc.cc:73
SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex
Definition: WinSvc.cc:48
time_t getCurrentTime(void)
Get current time.
static FILE * logfile
void rewind(const int aSection, const int aLevel)
Optimization: avoids new Context creation for every debugs().
Definition: debug.cc:797
int KidIdentifier
static std::ostringstream & Start(const int section, const int level)
opens debugging context and returns output buffer
Definition: debug.cc:823
void printHex(std::ostream &os) const
print data bytes using hex notation
Definition: debug.cc:874
void ResyncDebugLog(FILE *newFile)
a hack for low-level file descriptor manipulations in ipcCreate()
Definition: debug.cc:88
static void ctx_print(void)
Definition: debug.cc:745
static const char * debugLogKid(void)
Definition: debug.cc:600
static int Levels[MAX_DEBUG_SECTIONS]
Definition: Debug.h:83
#define DBG_DATA
Definition: Debug.h:48
static int SectionLevel()
maximum level currently allowed
Definition: Debug.h:93
static int Ctx_Lock
Definition: debug.cc:29
void clear()
go back to the initial state
Definition: debug.cc:59
#define xfree
FILE * DebugStream()
Definition: debug.cc:77
static int Ctx_Valid_Level
Definition: debug.cc:706
FILE * file()
logging stream; the only method that uses stderr as the last resort
Definition: debug.cc:62
static const char * ctx_get_descr(Ctx ctx)
Definition: debug.cc:776
#define NULL
Definition: types.h:166
static void _db_print(const bool forceAlert, const char *format,...)
Definition: debug.cc:113
static DebugFile TheLog
Definition: debug.cc:74
#define APP_SHORTNAME
Definition: version.h:19
~DebugFile()
Definition: debug.cc:52
#define false
Definition: GnuRegex.c:233
int Ctx
Definition: Debug.h:37
#define MAX_DEBUG_SECTIONS
Definition: Debug.h:42
bool forceAlert
the current debugs() will be a syslog ALERT
Definition: Debug.h:71

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors