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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors