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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors