debug.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 "base/TextException.h"
13 #include "comm.h"
14 #include "debug/Stream.h"
15 #include "fatal.h"
16 #include "fd.h"
17 #include "ipc/Kids.h"
18 #include "time/gadgets.h"
19 #include "util.h"
20 
21 #include <algorithm>
22 #include <deque>
23 #include <functional>
24 #include <memory>
25 #include <optional>
26 
27 char *Debug::debugOptions = nullptr;
28 int Debug::override_X = 0;
29 bool Debug::log_syslog = false;
31 char *Debug::cache_log = nullptr;
32 int Debug::rotateNumber = -1;
33 
35 using DebugRecordCount = uint64_t;
36 
37 class DebugModule;
38 
40 static DebugModule *Module_ = nullptr;
41 
45 static std::optional<int> ExplicitStderrLevel;
46 
53 static int DefaultStderrLevel = -1;
54 
56 static constexpr int EarlyMessagesLevel = DBG_IMPORTANT;
57 
59 static std::string ProcessLabel;
60 
61 static const char *debugLogTime(const timeval &);
62 
63 #if HAVE_SYSLOG
64 #ifdef LOG_LOCAL4
65 static int syslog_facility = 0;
66 #endif
67 #endif
68 
69 #if _SQUID_WINDOWS_
70 extern LPCRITICAL_SECTION dbg_mutex;
71 typedef BOOL (WINAPI * PFInitializeCriticalSectionAndSpinCount) (LPCRITICAL_SECTION, DWORD);
72 #endif
73 
74 static void ResetSections(const int level = DBG_IMPORTANT);
75 
80 static bool DidResetSections = false;
81 
83 class DebugFile
84 {
85 public:
86  DebugFile() {}
87  ~DebugFile() { clear(); }
88  DebugFile(DebugFile &&) = delete; // no copying or moving of any kind
89 
91  void reset(FILE *newFile, const char *newName);
92 
94  void clear() { reset(nullptr, nullptr); }
95 
97  FILE *file() { return file_; }
98 
99  char *name = nullptr;
100 
101 private:
102  friend void ResyncDebugLog(FILE *newFile);
103 
104  FILE *file_ = nullptr;
105 };
106 
109 {
110 public:
111  DebugMessageHeader(const DebugRecordCount aRecordNumber, const Debug::Context &);
112 
114  struct timeval timestamp;
115  int section;
116  int level;
117  bool forceAlert;
118 };
119 
120 // Avoid SBuf for CompiledDebugMessageBody:
121 // * SBuf's own debugging may create a lot of reentrant debugging noise.
122 // * Debug::Context::buf is an std::string-based STL ostream. Converting its
123 // buf() result to a different kind of string may increase complexity/cost.
124 // TODO: Consider switching to a simple fixed-size buffer and a matching stream!
126 using CompiledDebugMessageBody = std::string;
127 
130 {
131 public:
134 
135  CompiledDebugMessage(const Header &, const Body &);
136 
139 };
140 
141 // We avoid PoolingAllocator for CompiledDebugMessages to minimize reentrant
142 // debugging noise. This noise reduction has negligible performance overhead
143 // because it only applied to early messages, and there are few of them.
145 using CompiledDebugMessages = std::deque<CompiledDebugMessage>;
146 
149 {
150 public:
151  using EarlyMessages = std::unique_ptr<CompiledDebugMessages>;
152 
153  explicit DebugChannel(const char *aName);
154  virtual ~DebugChannel() = default;
155 
156  // no copying or moving or any kind (for simplicity sake and to prevent accidental copies)
157  DebugChannel(DebugChannel &&) = delete;
158 
160  bool collectingEarlyMessages() const { return bool(earlyMessages); }
161 
164 
168 
171  void log(const DebugMessageHeader &, const CompiledDebugMessageBody &);
172 
173 protected:
175  class Logger
176  {
177  public:
178  using difference_type = void;
179  using value_type = void;
180  using pointer = void;
181  using reference = void;
182  using iterator_category = std::output_iterator_tag;
183 
184  explicit Logger(DebugChannel &ch): channel(ch) {}
185 
187  {
188  if (Debug::Enabled(message.header.section, message.header.level))
189  channel.get().log(message.header, message.body);
190  return *this;
191  }
192 
193  // These no-op operators are provided to satisfy LegacyOutputIterator requirements,
194  // as is customary for similar STL output iterators like std::ostream_iterator.
195  Logger &operator*() { return *this; }
196  Logger &operator++() { return *this; }
197  Logger &operator++(int) { return *this; }
198 
199  private:
200  // wrap: output iterators must be CopyAssignable; raw references are not
201  std::reference_wrapper<DebugChannel> channel;
202  };
203 
206  virtual bool shouldWrite(const DebugMessageHeader &) const = 0;
207 
209  virtual void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) = 0;
210 
213 
215  static void StopSavingAndLog(DebugChannel &, DebugChannel * = nullptr);
216 
218  void writeToStream(FILE &, const DebugMessageHeader &, const CompiledDebugMessageBody &);
219 
221  void noteWritten(const DebugMessageHeader &);
222 
223 protected:
224  const char * const name = nullptr;
225 
228 
231 
236 };
237 
240 {
241 public:
242  CacheLogChannel(): DebugChannel("cache_log") {}
243 
244 protected:
245  /* DebugChannel API */
246  bool shouldWrite(const DebugMessageHeader &) const final;
247  void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final;
248 };
249 
252 {
253 public:
254  StderrChannel(): DebugChannel("stderr") {}
255 
257  void takeOver(CacheLogChannel &);
258 
261 
263  bool enabled(const int messageDebugLevel) const;
264 
265 protected:
266  /* DebugChannel API */
267  bool shouldWrite(const DebugMessageHeader &) const final;
268  void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final;
269 
270 private:
272  bool coveringForCacheLog = false;
273 };
274 
277 {
278 public:
279  SyslogChannel(): DebugChannel("syslog") {}
280 
281  void markOpened() { opened = true; }
282 
283 protected:
284  /* DebugChannel API */
285  bool shouldWrite(const DebugMessageHeader &) const final;
286  void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final;
287 
288 private:
289  bool opened = false;
290 };
291 
297 {
298 public:
299  DebugModule();
300 
301  // we provide debugging services for the entire duration of the program
302  ~DebugModule() = delete;
303 
305  void prepareToDie();
306 
309  void log(const DebugMessageHeader &, const CompiledDebugMessageBody &);
310 
313  void useCacheLog();
314 
317  void banCacheLogUse();
318 
319 public:
323 };
324 
330 {
331 public:
334 
336  static bool Busy() { return LoggingConcurrencyLevel; }
337 
338 private:
340  static size_t LoggingConcurrencyLevel;
341 };
342 
344 
347 static Debug::Context *WaitingForIdle = nullptr;
348 
353 
354 FILE *
356  return TheLog.file() ? TheLog.file() : stderr;
357 }
358 
360 static void
361 ResetSections(const int level)
362 {
363  DidResetSections = true;
364  for (auto &sectionLevel: Debug::Levels)
365  sectionLevel = level;
366 }
367 
369 static void
370 LabelThisProcess(const char * const name, const std::optional<int> id = std::optional<int>())
371 {
372  assert(name);
373  assert(strlen(name));
374  std::stringstream os;
375  os << ' ' << name;
376  if (id.has_value()) {
377  assert(id.value() >= 0);
378  os << id.value();
379  }
380  ProcessLabel = os.str();
381 }
382 
383 void
384 Debug::NameThisHelper(const char * const name)
385 {
386  LabelThisProcess(name);
387 
388  if (const auto parentProcessDebugOptions = getenv("SQUID_DEBUG")) {
390  debugOptions = xstrdup(parentProcessDebugOptions);
391  }
392 
393  // do not restrict helper (i.e. stderr) logging beyond debug_options
395 
396  // helpers do not write to cache.log directly; instead, ipcCreate()
397  // diverts helper stderr output to cache.log of the parent process
398  BanCacheLogUse();
399 
400  SettleStderr();
401  SettleSyslog();
402 
403  debugs(84, 2, "starting " << name << " with PID " << getpid());
404 }
405 
406 void
407 Debug::NameThisKid(const int kidIdentifier)
408 {
409  // to reduce noise and for backward compatibility, do not label kid messages
410  // in non-SMP mode
411  if (kidIdentifier)
412  LabelThisProcess("kid", std::optional<int>(kidIdentifier));
413  else
414  ProcessLabel.clear(); // probably already empty
415 }
416 
417 /* LoggingSectionGuard */
418 
420 {
422 }
423 
425 {
426  if (--LoggingConcurrencyLevel == 0)
428 }
429 
430 /* DebugModule */
431 
432 // Depending on DBG_CRITICAL activity and command line options, this code may
433 // run as early as static initialization during program startup or as late as
434 // the first debugs(DBG_CRITICAL) call from the main loop.
436 {
437  // explicit initialization before any use by debugs() calls; see bug #2656
438  tzset();
439 
440  (void)std::atexit(&Debug::PrepareToDie);
441 
442  if (!DidResetSections)
443  ResetSections();
444 }
445 
446 void
448 {
449  cacheLogChannel.log(header, body);
450  stderrChannel.log(header, body);
451  syslogChannel.log(header, body);
452 }
453 
454 void
456 {
457  const LoggingSectionGuard sectionGuard;
458 
459  // Switch to stderr to improve our chances to log _early_ debugs(). However,
460  // use existing cache_log and/or stderr levels for post-open/close ones.
462  banCacheLogUse();
463 
467 
468  // Explicit last-resort call because we want to dump any pending messages
469  // (possibly including an assertion) even if another call, higher in the
470  // call stack, is currently in the sensitive section. Squid is dying, and
471  // that other caller (if any) will not get control back and, hence, will not
472  // trigger a Debug::LogWaitingForIdle() check. In most cases, we will log
473  // any pending messages successfully here. In the remaining few cases, we
474  // will lose them just like we would lose them without this call. The
475  // (small) risk here is that we might abort() or crash trying.
477 
478  // Do not close/destroy channels: While the Debug module is not _guaranteed_
479  // to get control after prepareToDie(), debugs() calls are still very much
480  // _possible_, and we want to support/log them for as long as we can.
481 }
482 
483 void
485 {
486  assert(TheLog.file());
487  stderrChannel.stopCoveringForCacheLog(); // in case it was covering
488  cacheLogChannel.stopEarlyMessageCollection(); // in case it was collecting
489 }
490 
491 void
493 {
494  assert(!TheLog.file());
496 }
497 
499 static
500 DebugModule &
502 {
503  if (!Module_) {
504  Module_ = new DebugModule();
505 #if !HAVE_SYSLOG
506  // Optimization: Do not wait for others to tell us what we already know.
508 #endif
509  }
510 
511  return *Module_;
512 }
513 
514 void
515 ResyncDebugLog(FILE *newFile)
516 {
517  TheLog.file_ = newFile;
518 }
519 
520 /* DebugChannel */
521 
522 DebugChannel::DebugChannel(const char * const aName):
523  name(aName),
524  earlyMessages(new CompiledDebugMessages())
525 {
526 }
527 
528 void
530 {
531  if (earlyMessages)
532  StopSavingAndLog(*this);
533  // else already stopped
534 }
535 
536 void
538 {
540  return;
541 
542  if (!shouldWrite(header))
543  return saveMessage(header, body);
544 
545  // We only save messages until we learn whether the channel is going to be
546  // used. We now know that it will be used. Also logs saved early messages
547  // (if they became eligible now) before lastWrittenRecordNumber blocks them.
549 
550  write(header, body);
551 }
552 
553 void
555 {
556  auto &module = Module();
557  (void)module.cacheLogChannel.releaseEarlyMessages();
558  (void)module.stderrChannel.releaseEarlyMessages();
559  (void)module.syslogChannel.releaseEarlyMessages();
560 }
561 
562 void
564 {
565  Module().prepareToDie();
566 }
567 
568 void
570 {
571  const LoggingSectionGuard sectionGuard;
572 
573  assert(&channelA != channelBOrNil);
574  const auto asOrNil = channelA.releaseEarlyMessages();
575  const auto bsOrNil = channelBOrNil ? channelBOrNil->releaseEarlyMessages() : nullptr;
576  const auto &as = asOrNil ? *asOrNil : CompiledDebugMessages();
577  const auto &bs = bsOrNil ? *bsOrNil : CompiledDebugMessages();
578 
579  const auto writtenEarlier = channelA.written;
580 
581  std::merge(as.begin(), as.end(), bs.begin(), bs.end(), Logger(channelA),
582  [](const CompiledDebugMessage &mA, const CompiledDebugMessage &mB) {
583  return mA.header.recordNumber < mB.header.recordNumber;
584  });
585 
586  const auto writtenNow = channelA.written - writtenEarlier;
587  if (const auto totalCount = as.size() + bs.size()) {
588  debugs(0, 5, "wrote " << writtenNow << " out of " << totalCount << '=' <<
589  as.size() << '+' << bs.size() << " early messages to " << channelA.name);
590  }
591 }
592 
593 void
595 {
596  if (!earlyMessages)
597  return; // we have stopped saving early messages
598 
599  if (header.level > EarlyMessagesLevel)
600  return; // this message is not important enough to save
601 
602  // Given small EarlyMessagesLevel, only a Squid bug can cause so many
603  // earlyMessages. Saving/dumping excessive messages correctly is not only
604  // difficult but is more likely to complicate triage than help: It is the
605  // first earlyMessages that are going to be the most valuable. Our assert()
606  // will dump them if at all possible.
607  assert(earlyMessages->size() < 1000);
608 
609  earlyMessages->emplace_back(header, body);
610 }
611 
612 void
613 DebugChannel::writeToStream(FILE &destination, const DebugMessageHeader &header, const CompiledDebugMessageBody &body)
614 {
615  fprintf(&destination, "%s%s| %s\n",
616  debugLogTime(header.timestamp),
617  ProcessLabel.c_str(),
618  body.c_str());
619  noteWritten(header);
620 }
621 
622 void
624 {
625  ++written;
627 }
628 
629 /* CacheLogChannel */
630 
631 bool
633 {
634  return TheLog.file();
635 }
636 
637 void
639 {
640  writeToStream(*TheLog.file(), header, body);
641  fflush(TheLog.file());
642 }
643 
644 /* StderrChannel */
645 
646 bool
647 StderrChannel::enabled(const int level) const
648 {
649  if (!stderr)
650  return false; // nowhere to write
651 
652  if (ExplicitStderrLevel.has_value()) // explicit admin restrictions (-d)
653  return level <= ExplicitStderrLevel.value();
654 
655  // whether the given level is allowed by emergency handling circumstances
656  // (coveringForCacheLog) or configuration aspects (e.g., -k or -z)
657  return coveringForCacheLog || level <= DefaultStderrLevel;
658 }
659 
660 bool
662 {
663  return enabled(header.level);
664 }
665 
666 void
668 {
669  writeToStream(*stderr, header, body);
670 }
671 
672 void
674 {
676  return;
677  coveringForCacheLog = true;
678 
679  StopSavingAndLog(*this, &cacheLogChannel);
680 }
681 
682 void
684 {
685  if (!coveringForCacheLog)
686  return;
687 
688  coveringForCacheLog = false;
689  debugs(0, DBG_IMPORTANT, "Resuming logging to cache_log");
690 }
691 
692 void
693 Debug::EnsureDefaultStderrLevel(const int maxDefault)
694 {
695  if (DefaultStderrLevel < maxDefault)
696  DefaultStderrLevel = maxDefault; // may set or increase
697  // else: somebody has already requested a more permissive maximum
698 }
699 
700 void
701 Debug::ResetStderrLevel(const int maxLevel)
702 {
703  ExplicitStderrLevel = maxLevel; // may set, increase, or decrease
704 }
705 
706 void
708 {
709  auto &stderrChannel = Module().stderrChannel;
710 
711  stderrChannel.stopEarlyMessageCollection();
712 
713  if (override_X) {
714  // Some users might expect -X to force -d9. Tell them what is happening.
715  const auto outcome =
716  stderrChannel.enabled(DBG_DATA) ? "; stderr will see all messages":
717  stderrChannel.enabled(DBG_CRITICAL) ? "; stderr will not see some messages":
718  "; stderr will see no messages";
720  debugs(0, DBG_CRITICAL, "Using -X and -d" << ExplicitStderrLevel.value() << outcome);
721  else
722  debugs(0, DBG_CRITICAL, "Using -X without -d" << outcome);
723  }
724 }
725 
726 bool
728 {
730 }
731 
732 /* DebugMessageHeader */
733 
735  recordNumber(aRecordNumber),
736  section(context.section),
737  level(context.level),
738  forceAlert(context.forceAlert)
739 {
740  (void)getCurrentTime(); // update current_time
742 }
743 
744 /* CompiledDebugMessage */
745 
747  header(aHeader),
748  body(aBody)
749 {
750 }
751 
752 /* DebugFile */
753 
754 void
755 DebugFile::reset(FILE *newFile, const char *newName)
756 {
757  // callers must use nullptr instead of the used-as-the-last-resort stderr
758  assert(newFile != stderr || !stderr);
759 
760  if (file_) {
761  fd_close(fileno(file_));
762  fclose(file_);
763  }
764  file_ = newFile; // may be nil
765 
766  if (file_) {
767  commSetCloseOnExec(fileno(file_));
769  }
770 
771  xfree(name);
772  name = newName ? xstrdup(newName) : nullptr;
773 
774  // all open files must have a name
775  // all cleared files must not have a name
776  assert(!file_ == !name);
777 }
778 
780 void
781 Debug::LogMessage(const Context &context)
782 {
783 #if _SQUID_WINDOWS_
784  /* Multiple WIN32 threads may call this simultaneously */
785 
786  if (!dbg_mutex) {
787  HMODULE krnl_lib = GetModuleHandle("Kernel32");
788  PFInitializeCriticalSectionAndSpinCount InitializeCriticalSectionAndSpinCount = nullptr;
789 
790  if (krnl_lib)
791  InitializeCriticalSectionAndSpinCount =
792  (PFInitializeCriticalSectionAndSpinCount) GetProcAddress(krnl_lib,
793  "InitializeCriticalSectionAndSpinCount");
794 
795  dbg_mutex = static_cast<CRITICAL_SECTION*>(xcalloc(1, sizeof(CRITICAL_SECTION)));
796 
797  if (InitializeCriticalSectionAndSpinCount) {
798  /* let multiprocessor systems EnterCriticalSection() fast */
799 
800  if (!InitializeCriticalSectionAndSpinCount(dbg_mutex, 4000)) {
801  if (const auto logFile = TheLog.file()) {
802  fprintf(logFile, "FATAL: %s: can't initialize critical section\n", __func__);
803  fflush(logFile);
804  }
805 
806  fprintf(stderr, "FATAL: %s: can't initialize critical section\n", __func__);
807  abort();
808  } else
809  InitializeCriticalSection(dbg_mutex);
810  }
811  }
812 
813  EnterCriticalSection(dbg_mutex);
814 #endif
815 
816  static DebugRecordCount LogMessageCalls = 0;
817  const DebugMessageHeader header(++LogMessageCalls, context);
818  Module().log(header, context.buf.str());
819 
820 #if _SQUID_WINDOWS_
821  LeaveCriticalSection(dbg_mutex);
822 #endif
823 }
824 
825 static void
826 debugArg(const char *arg)
827 {
828  int s = 0;
829  int l = 0;
830 
831  if (!strncasecmp(arg, "rotate=", 7)) {
832  arg += 7;
833  Debug::rotateNumber = atoi(arg);
834  return;
835  } else if (!strncasecmp(arg, "ALL", 3)) {
836  s = -1;
837  arg += 4;
838  } else {
839  s = atoi(arg);
840  while (*arg && *arg++ != ',');
841  }
842 
843  l = atoi(arg);
844  assert(s >= -1);
845 
846  if (s >= MAX_DEBUG_SECTIONS)
847  s = MAX_DEBUG_SECTIONS-1;
848 
849  if (l < 0)
850  l = 0;
851 
852  if (l > 10)
853  l = 10;
854 
855  if (s >= 0) {
856  Debug::Levels[s] = l;
857  return;
858  }
859 
860  ResetSections(l);
861 }
862 
863 static void
864 debugOpenLog(const char *logfile)
865 {
866  assert(logfile);
867 
868  // Bug 4423: ignore the stdio: logging module name if present
869  const char *logfilename;
870  if (strncmp(logfile, "stdio:",6) == 0)
871  logfilename = logfile + 6;
872  else
873  logfilename = logfile;
874 
875  if (auto log = fopen(logfilename, "a+")) {
876 #if _SQUID_WINDOWS_
877  setmode(fileno(log), O_TEXT);
878 #endif
879  TheLog.reset(log, logfilename);
880  Module().useCacheLog();
881  } else {
882  const auto xerrno = errno;
883  TheLog.clear();
885 
886  // report the problem after banCacheLogUse() to improve our chances of
887  // reporting earlier debugs() messages (that cannot be written after us)
888  debugs(0, DBG_CRITICAL, "ERROR: Cannot open cache_log (" << logfilename << ") for writing;" <<
889  Debug::Extra << "fopen(3) error: " << xstrerr(xerrno));
890  }
891 }
892 
893 #if HAVE_SYSLOG
894 #ifdef LOG_LOCAL4
895 
896 static struct syslog_facility_name {
897  const char *name;
898  int facility;
899 }
900 
901 syslog_facility_names[] = {
902 
903 #ifdef LOG_AUTH
904  {
905  "auth", LOG_AUTH
906  },
907 #endif
908 #ifdef LOG_AUTHPRIV
909  {
910  "authpriv", LOG_AUTHPRIV
911  },
912 #endif
913 #ifdef LOG_CRON
914  {
915  "cron", LOG_CRON
916  },
917 #endif
918 #ifdef LOG_DAEMON
919  {
920  "daemon", LOG_DAEMON
921  },
922 #endif
923 #ifdef LOG_FTP
924  {
925  "ftp", LOG_FTP
926  },
927 #endif
928 #ifdef LOG_KERN
929  {
930  "kern", LOG_KERN
931  },
932 #endif
933 #ifdef LOG_LPR
934  {
935  "lpr", LOG_LPR
936  },
937 #endif
938 #ifdef LOG_MAIL
939  {
940  "mail", LOG_MAIL
941  },
942 #endif
943 #ifdef LOG_NEWS
944  {
945  "news", LOG_NEWS
946  },
947 #endif
948 #ifdef LOG_SYSLOG
949  {
950  "syslog", LOG_SYSLOG
951  },
952 #endif
953 #ifdef LOG_USER
954  {
955  "user", LOG_USER
956  },
957 #endif
958 #ifdef LOG_UUCP
959  {
960  "uucp", LOG_UUCP
961  },
962 #endif
963 #ifdef LOG_LOCAL0
964  {
965  "local0", LOG_LOCAL0
966  },
967 #endif
968 #ifdef LOG_LOCAL1
969  {
970  "local1", LOG_LOCAL1
971  },
972 #endif
973 #ifdef LOG_LOCAL2
974  {
975  "local2", LOG_LOCAL2
976  },
977 #endif
978 #ifdef LOG_LOCAL3
979  {
980  "local3", LOG_LOCAL3
981  },
982 #endif
983 #ifdef LOG_LOCAL4
984  {
985  "local4", LOG_LOCAL4
986  },
987 #endif
988 #ifdef LOG_LOCAL5
989  {
990  "local5", LOG_LOCAL5
991  },
992 #endif
993 #ifdef LOG_LOCAL6
994  {
995  "local6", LOG_LOCAL6
996  },
997 #endif
998 #ifdef LOG_LOCAL7
999  {
1000  "local7", LOG_LOCAL7
1001  },
1002 #endif
1003  {
1004  nullptr, 0
1005  }
1006 };
1007 
1008 #endif
1009 
1010 static void
1011 _db_set_syslog(const char *facility)
1012 {
1013  Debug::log_syslog = true;
1014 
1015 #ifdef LOG_LOCAL4
1016 #ifdef LOG_DAEMON
1017 
1018  syslog_facility = LOG_DAEMON;
1019 #else
1020 
1021  syslog_facility = LOG_LOCAL4;
1022 #endif /* LOG_DAEMON */
1023 
1024  if (facility) {
1025 
1026  struct syslog_facility_name *n;
1027 
1028  for (n = syslog_facility_names; n->name; ++n) {
1029  if (strcmp(n->name, facility) == 0) {
1030  syslog_facility = n->facility;
1031  return;
1032  }
1033  }
1034 
1035  fprintf(stderr, "unknown syslog facility '%s'\n", facility);
1036  exit(EXIT_FAILURE);
1037  }
1038 
1039 #else
1040  if (facility)
1041  fprintf(stderr, "syslog facility type not supported on your system\n");
1042 
1043 #endif /* LOG_LOCAL4 */
1044 }
1045 
1046 /* SyslogChannel */
1047 
1048 static int
1049 SyslogPriority(const DebugMessageHeader &header)
1050 {
1051  return header.forceAlert ? LOG_ALERT :
1052  (header.level == 0 ? LOG_WARNING : LOG_NOTICE);
1053 }
1054 
1055 void
1057 {
1058  syslog(SyslogPriority(header), "%s", body.c_str());
1059  noteWritten(header);
1060 }
1061 
1062 #else
1063 
1064 void
1066 {
1067  assert(!"unreachable code because opened, shouldWrite() are always false");
1068 }
1069 
1070 #endif /* HAVE_SYSLOG */
1071 
1072 bool
1074 {
1075  if (!opened)
1076  return false;
1077 
1079  return header.forceAlert || header.level <= DBG_IMPORTANT;
1080 }
1081 
1082 void
1083 Debug::ConfigureSyslog(const char *facility)
1084 {
1085 #if HAVE_SYSLOG
1086  _db_set_syslog(facility);
1087 #else
1088  (void)facility;
1089  // TODO: Throw.
1090  fatalf("Logging to syslog not available on this platform");
1091 #endif
1092 }
1093 
1094 void
1095 Debug::parseOptions(char const *options)
1096 {
1097  char *p = nullptr;
1098  char *s = nullptr;
1099 
1100  if (override_X) {
1101  debugs(0, 9, "command-line -X overrides: " << options);
1102  return;
1103  }
1104 
1105  ResetSections();
1106 
1107  if (options) {
1108  p = xstrdup(options);
1109 
1110  for (s = strtok(p, w_space); s; s = strtok(nullptr, w_space))
1111  debugArg(s);
1112 
1113  xfree(p);
1114  }
1115 }
1116 
1117 void
1119 {
1121  Module().banCacheLogUse();
1122 }
1123 
1124 void
1126 {
1129 }
1130 
1131 void
1133 {
1134  if (TheLog.file()) {
1135  // UseCacheLog() was successful.
1137  TheLog.clear();
1138  } else {
1139  // UseCacheLog() was not called at all or failed to open cache_log.
1140  Module().banCacheLogUse(); // may already be banned
1141  }
1142 }
1143 
1144 void
1146 {
1147 #if HAVE_SYSLOG && defined(LOG_LOCAL4)
1148 
1149  if (Debug::log_syslog) {
1150  openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, syslog_facility);
1152  }
1153 
1154 #endif /* HAVE_SYSLOG */
1155 
1157 }
1158 
1159 void
1161 {
1162  if (!TheLog.name)
1163  return;
1164 
1165 #ifdef S_ISREG
1166  struct stat sb;
1167  if (stat(TheLog.name, &sb) == 0)
1168  if (S_ISREG(sb.st_mode) == 0)
1169  return;
1170 #endif
1171 
1172  char from[MAXPATHLEN];
1173  from[0] = '\0';
1174 
1175  char to[MAXPATHLEN];
1176  to[0] = '\0';
1177 
1178  /*
1179  * NOTE: we cannot use xrename here without having it in a
1180  * separate file -- tools.c has too many dependencies to be
1181  * used everywhere debug.c is used.
1182  */
1183  /* Rotate numbers 0 through N up one */
1184  for (int i = Debug::rotateNumber; i > 1;) {
1185  --i;
1186  snprintf(from, MAXPATHLEN, "%s.%d", TheLog.name, i - 1);
1187  snprintf(to, MAXPATHLEN, "%s.%d", TheLog.name, i);
1188 #if _SQUID_WINDOWS_
1189  remove
1190  (to);
1191 #endif
1192  errno = 0;
1193  if (rename(from, to) == -1) {
1194  const auto saved_errno = errno;
1195  debugs(0, DBG_IMPORTANT, "ERROR: log rotation failed: " << xstrerr(saved_errno));
1196  }
1197  }
1198 
1199  /* Rotate the current log to .0 */
1200  if (Debug::rotateNumber > 0) {
1201  // form file names before we may clear TheLog below
1202  snprintf(from, MAXPATHLEN, "%s", TheLog.name);
1203  snprintf(to, MAXPATHLEN, "%s.%d", TheLog.name, 0);
1204 
1205 #if _SQUID_WINDOWS_
1206  errno = 0;
1207  if (remove(to) == -1) {
1208  const auto saved_errno = errno;
1209  debugs(0, DBG_IMPORTANT, "ERROR: removal of log file " << to << " failed: " << xstrerr(saved_errno));
1210  }
1211  TheLog.clear(); // Windows cannot rename() open files
1212 #endif
1213  errno = 0;
1214  if (rename(from, to) == -1) {
1215  const auto saved_errno = errno;
1216  debugs(0, DBG_IMPORTANT, "ERROR: renaming file " << from << " to "
1217  << to << "failed: " << xstrerr(saved_errno));
1218  }
1219  }
1220 
1221  // Close (if we have not already) and reopen the log because
1222  // it may have been renamed "manually" before HUP'ing us.
1224 }
1225 
1226 static const char *
1227 debugLogTime(const timeval &t)
1228 {
1229  static char buf[128]; // arbitrary size, big enough for the below timestamp strings.
1230  static time_t last_t = 0;
1231 
1232  if (Debug::Level() > 1) {
1233  last_t = t.tv_sec;
1234  // 4 bytes smaller than buf to ensure .NNN catenation by snprintf()
1235  // is safe and works even if strftime() fills its buffer.
1236  char buf2[sizeof(buf)-4];
1237  const auto tm = localtime(&last_t);
1238  strftime(buf2, sizeof(buf2), "%Y/%m/%d %H:%M:%S", tm);
1239  buf2[sizeof(buf2)-1] = '\0';
1240  const auto sz = snprintf(buf, sizeof(buf), "%s.%03d", buf2, static_cast<int>(t.tv_usec / 1000));
1241  assert(0 < sz && sz < static_cast<int>(sizeof(buf)));
1242  // force buf reset for subsequent level-0/1 messages that should have no milliseconds
1243  last_t = 0;
1244  } else if (t.tv_sec != last_t) {
1245  last_t = t.tv_sec;
1246  const auto tm = localtime(&last_t);
1247  const int sz = strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", tm);
1248  assert(0 < sz && sz <= static_cast<int>(sizeof(buf)));
1249  }
1250 
1251  buf[sizeof(buf)-1] = '\0';
1252  return buf;
1253 }
1254 
1257 static auto Asserting_ = false;
1258 
1259 void
1260 xassert(const char *msg, const char *file, int line)
1261 {
1262  // if the non-trivial code below has itself asserted, then simplify instead
1263  // of running out of stack and complicating triage
1264  if (Asserting_)
1265  abort();
1266 
1267  Asserting_ = true;
1268 
1269  debugs(0, DBG_CRITICAL, "FATAL: assertion failed: " << file << ":" << line << ": \"" << msg << "\"");
1270 
1272  abort();
1273 }
1274 
1275 Debug::Context *Debug::Current = nullptr;
1276 
1277 Debug::Context::Context(const int aSection, const int aLevel):
1278  section(aSection),
1279  level(aLevel),
1280  sectionLevel(Levels[aSection]),
1281  upper(Current),
1282  forceAlert(false),
1283  waitingForIdle(false)
1284 {
1285  FormatStream(buf);
1286 }
1287 
1289 void
1290 Debug::Context::rewind(const int aSection, const int aLevel)
1291 {
1292  section = aSection;
1293  level = aLevel;
1294  sectionLevel = Levels[aSection];
1295  assert(upper == Current);
1296  assert(!waitingForIdle);
1297 
1298  buf.str(CompiledDebugMessageBody());
1299  buf.clear();
1300  FormatStream(buf);
1301 }
1302 
1304 void
1305 Debug::FormatStream(std::ostream &buf)
1306 {
1307  const static std::ostringstream cleanStream;
1308  buf.flags(cleanStream.flags() | std::ios::fixed);
1309  buf.width(cleanStream.width());
1310  buf.precision(2);
1311  buf.fill(' ');
1312  // If this is not enough, use copyfmt(cleanStream) which is ~10% slower.
1313 }
1314 
1315 std::ostream &
1316 Debug::Extra(std::ostream &os)
1317 {
1318  // Prevent previous line formats bleeding onto this line: Previous line code
1319  // may not even be aware of some detailing code automatically adding extras.
1320  FormatStream(os);
1321 
1322  os << "\n ";
1323  return os;
1324 }
1325 
1326 void
1328 {
1329  if (!WaitingForIdle)
1330  return; // do not lock in vain because unlocking would calls us
1331 
1332  const LoggingSectionGuard sectionGuard;
1333  while (const auto current = WaitingForIdle) {
1334  assert(current->waitingForIdle);
1335  LogMessage(*current);
1336  WaitingForIdle = current->upper;
1337  delete current;
1338  }
1339 }
1340 
1341 std::ostringstream &
1342 Debug::Start(const int section, const int level)
1343 {
1344  Context *future = nullptr;
1345 
1346  if (LoggingSectionGuard::Busy()) {
1347  // a very rare reentrant debugs() call that originated during Finish() and such
1348  future = new Context(section, level);
1349  future->waitingForIdle = true;
1350  } else if (Current) {
1351  // a rare reentrant debugs() call that originated between Start() and Finish()
1352  future = new Context(section, level);
1353  } else {
1354  // Optimization: Nearly all debugs() calls get here; avoid allocations
1355  static Context *topContext = new Context(1, 1);
1356  topContext->rewind(section, level);
1357  future = topContext;
1358  }
1359 
1360  Current = future;
1361 
1362  return future->buf;
1363 }
1364 
1365 void
1367 {
1368  const LoggingSectionGuard sectionGuard;
1369 
1370  // TODO: #include "base/CodeContext.h" instead if doing so works well.
1371  extern std::ostream &CurrentCodeContextDetail(std::ostream &os);
1372  if (Current->level <= DBG_IMPORTANT)
1374 
1375  if (Current->waitingForIdle) {
1376  const auto past = Current;
1377  Current = past->upper;
1378  past->upper = nullptr;
1379  // do not delete `past` because we store it in WaitingForIdle below
1380 
1381  // waitingForIdle messages are queued here instead of Start() because
1382  // their correct order is determined by the Finish() call timing/order.
1383  // Linear search, but this list ought to be very short (usually empty).
1384  auto *last = &WaitingForIdle;
1385  while (*last)
1386  last = &(*last)->upper;
1387  *last = past;
1388 
1389  return;
1390  }
1391 
1392  LogMessage(*Current);
1393  Current->forceAlert = false;
1394 
1395  Context *past = Current;
1396  Current = past->upper;
1397  if (Current)
1398  delete past;
1399  // else it was a static topContext from Debug::Start()
1400 }
1401 
1402 void
1404 {
1405  // the ForceAlert(ostream) manipulator should only be used inside debugs()
1406  if (Current)
1407  Current->forceAlert = true;
1408 }
1409 
1410 std::ostream&
1411 ForceAlert(std::ostream& s)
1412 {
1414  return s;
1415 }
1416 
static char * debugOptions
Definition: Stream.h:80
const char * xstrerr(int error)
Definition: xstrerror.cc:83
static char * cache_log
Definition: Stream.h:81
virtual ~DebugChannel()=default
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
std::deque< CompiledDebugMessage > CompiledDebugMessages
debugs() messages captured in LogMessage() call order
Definition: debug.cc:145
bool forceAlert
the current debugs() will be a syslog ALERT
Definition: Stream.h:67
#define DBG_CRITICAL
Definition: Stream.h:37
void takeOver(CacheLogChannel &)
start to take care of past/saved and future cacheLovirtual gChannel messages
Definition: debug.cc:673
output iterator for writing CompiledDebugMessages to a given channel
Definition: debug.cc:175
CacheLogChannel cacheLogChannel
Definition: debug.cc:320
DebugRecordCount recordNumber
LogMessage() calls before this message.
Definition: debug.cc:113
static DebugModule & Module()
safe access to the debugging module
Definition: debug.cc:501
Header header
debugs() meta-information; reflected in log line prefix
Definition: debug.cc:137
SyslogChannel()
Definition: debug.cc:279
Logger & operator++(int)
Definition: debug.cc:197
std::ostringstream buf
debugs() output sink
Definition: Stream.h:66
static void FormatStream(std::ostream &)
configures default formatting for the debugging stream
Definition: debug.cc:1305
int level
debugs() level
Definition: debug.cc:116
static void NameThisKid(int kidIdentifier)
Definition: debug.cc:407
static void LogWaitingForIdle()
Logs messages of Finish()ed debugs() calls that were queued earlier.
Definition: debug.cc:1327
void commSetCloseOnExec(int)
Definition: minimal.cc:27
DebugChannel managing messages destined for the configured cache_log file.
Definition: debug.cc:239
void log(char *format,...)
Body body
the log line after the prefix (without the newline)
Definition: debug.cc:138
void noteWritten(const DebugMessageHeader &)
reacts to a written a debugs() message
Definition: debug.cc:623
SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex
#define O_TEXT
Definition: defines.h:131
DebugMessageHeader(const DebugRecordCount aRecordNumber, const Debug::Context &)
Definition: debug.cc:734
DebugChannel(const char *aName)
Definition: debug.cc:522
static void ResetStderrLevel(int maxLevel)
Definition: debug.cc:701
static std::optional< int > ExplicitStderrLevel
Definition: debug.cc:45
static size_t LoggingConcurrencyLevel
the current number of protected callers
Definition: debug.cc:340
static void StopSavingAndLog(DebugChannel &, DebugChannel *=nullptr)
stop saving and log() any "early" messages, in recordNumber order
Definition: debug.cc:569
FILE * file()
an opened cache_log stream or nil
Definition: debug.cc:97
std::unique_ptr< CompiledDebugMessages > EarlyMessages
Definition: debug.cc:151
#define xstrdup
@ FD_LOG
Definition: enums.h:14
syslog DebugChannel
Definition: debug.cc:276
std::string CompiledDebugMessageBody
The processed "content" (i.e. the last parameter) part of a debugs() call.
Definition: debug.cc:126
~DebugModule()=delete
a fully processed debugs(), ready to be logged
Definition: debug.cc:129
Context(const int aSectionLevel, const int aLevel)
Definition: debug.cc:1277
static void ConfigureSyslog(const char *facility)
enables logging to syslog (using the specified facility, when not nil)
Definition: debug.cc:1083
EarlyMessages releaseEarlyMessages()
Definition: debug.cc:167
static std::ostringstream & Start(const int section, const int level)
opens debugging context and returns output buffer
Definition: debug.cc:1342
static void debugOpenLog(const char *logfile)
Definition: debug.cc:864
static char last
Definition: parse.c:451
void fd_open(const int fd, unsigned int, const char *description)
Definition: minimal.cc:15
#define w_space
Logger & operator=(const CompiledDebugMessage &message)
Definition: debug.cc:186
DebugRecordCount written
the number of messages sent to the underlying channel so far
Definition: debug.cc:227
virtual void write(const DebugMessageHeader &, const CompiledDebugMessageBody &)=0
write the corresponding debugs() message into the channel
static void UseCacheLog()
Definition: debug.cc:1125
CompiledDebugMessageBody Body
Definition: debug.cc:133
const char *const name
unique channel label for debugging
Definition: debug.cc:224
StderrChannel()
Definition: debug.cc:254
bool enabled(const int messageDebugLevel) const
Definition: debug.cc:647
void clear()
go back to the initial state
Definition: debug.cc:94
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
Definition: Stream.h:75
#define DBG_DATA
Definition: Stream.h:40
static bool Busy()
whether new debugs() messages must be queued
Definition: debug.cc:336
int level
minimum debugging level required by the debugs() call
Definition: Stream.h:57
#define APP_SHORTNAME
Definition: version.h:22
static Debug::Context * WaitingForIdle
Definition: debug.cc:347
int section
debugs() section
Definition: debug.cc:115
static int DefaultStderrLevel
Definition: debug.cc:53
~DebugFile()
Definition: debug.cc:87
static int Levels[MAX_DEBUG_SECTIONS]
Definition: Stream.h:83
virtual bool shouldWrite(const DebugMessageHeader &) const =0
static void debugArg(const char *arg)
Definition: debug.cc:826
static constexpr int EarlyMessagesLevel
early debugs() with higher level are not buffered and, hence, may be lost
Definition: debug.cc:56
bool collectingEarlyMessages() const
whether we are still expecting (and buffering) early messages
Definition: debug.cc:160
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:18
time_t getCurrentTime() STUB_RETVAL(0) int tvSubUsec(struct timeval
CompiledDebugMessage(const Header &, const Body &)
Definition: debug.cc:746
meta-information for debugs() or a similar debugging call
Definition: Stream.h:51
DebugModule()
Definition: debug.cc:435
static void ForgetSaved()
silently erases saved early debugs() messages (if any)
Definition: debug.cc:554
void xassert(const char *msg, const char *file, int line)
Definition: debug.cc:1260
static void NameThisHelper(const char *name)
Definition: debug.cc:384
static void Finish()
logs output buffer created in Start() and closes debugging context
Definition: debug.cc:1366
static DebugModule * Module_
Debugging module singleton.
Definition: debug.cc:40
void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final
write the corresponding debugs() message into the channel
Definition: debug.cc:1065
DebugRecordCount lastWrittenRecordNumber
DebugMessageHeader::recordNumber of the last message we wrote.
Definition: debug.cc:230
Context * upper
previous or parent record in nested debugging calls
Definition: Stream.h:65
static void EnsureDefaultStderrLevel(int maxDefault)
Definition: debug.cc:693
a receiver of debugs() messages (e.g., stderr or cache.log)
Definition: debug.cc:148
void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final
write the corresponding debugs() message into the channel
Definition: debug.cc:638
static DebugFile TheLog
Definition: debug.cc:352
void stopCoveringForCacheLog()
stop providing a cache_log replacement (if we were providing it)
Definition: debug.cc:683
bool forceAlert
debugs() forceAlert flag
Definition: debug.cc:117
static bool StderrEnabled()
Definition: debug.cc:727
void stopEarlyMessageCollection()
end early message buffering, logging any saved messages
Definition: debug.cc:529
#define assert(EX)
Definition: assert.h:17
meta-information of a Finish()ed debugs() message
Definition: debug.cc:108
static void PrepareToDie()
Definition: debug.cc:563
static void parseOptions(char const *)
Definition: debug.cc:1095
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
static int rotateNumber
Definition: Stream.h:82
void markOpened()
Definition: debug.cc:281
void log(const DebugMessageHeader &, const CompiledDebugMessageBody &)
Definition: debug.cc:537
bool coveringForCacheLog
whether we are the last resort for logging debugs() messages
Definition: debug.cc:272
std::ostream & CurrentCodeContextDetail(std::ostream &os)
Definition: CodeContext.cc:96
FILE * DebugStream()
Definition: debug.cc:355
void _db_rotate_log(void)
Definition: debug.cc:1160
void reset(FILE *newFile, const char *newName)
switches to the new pair, absorbing FILE and duping the name
Definition: debug.cc:755
bool shouldWrite(const DebugMessageHeader &) const final
Definition: debug.cc:661
std::reference_wrapper< DebugChannel > channel
output destination
Definition: debug.cc:201
void prepareToDie()
Definition: debug.cc:455
void banCacheLogUse()
Definition: debug.cc:492
static const char * debugLogTime(const timeval &)
Definition: debug.cc:1227
static void ResetSections(const int level=DBG_IMPORTANT)
used for the side effect: fills Debug::Levels with the given level
Definition: debug.cc:361
SyslogChannel syslogChannel
Definition: debug.cc:322
static std::ostream & Extra(std::ostream &)
Definition: debug.cc:1316
#define xfree
static bool log_syslog
Definition: Stream.h:85
#define MAX_DEBUG_SECTIONS
Definition: Stream.h:34
void rewind(const int aSection, const int aLevel)
Optimization: avoids new Context creation for every debugs().
Definition: debug.cc:1290
DebugChannel managing messages destined for "standard error stream" (stderr)
Definition: debug.cc:251
bool shouldWrite(const DebugMessageHeader &) const final
Definition: debug.cc:632
friend void ResyncDebugLog(FILE *newFile)
a hack for low-level file descriptor manipulations in ipcCreate()
Definition: debug.cc:515
bool waitingForIdle
Definition: Stream.h:71
void log(const DebugMessageHeader &, const CompiledDebugMessageBody &)
Definition: debug.cc:447
static void SettleStderr()
Definition: debug.cc:707
struct timeval timestamp
approximate debugs() call time
Definition: debug.cc:114
static void LogMessage(const Context &)
broadcasts debugs() message to the logging channels
Definition: debug.cc:781
static void ForceAlert()
configures the active debugging context to write syslog ALERT
Definition: debug.cc:1403
static std::string ProcessLabel
pre-formatted name of the current process for debugs() messages (or empty)
Definition: debug.cc:59
static int Level()
minimum level required by the current debugs() call
Definition: Stream.h:100
static void SettleSyslog()
Definition: debug.cc:1145
void useCacheLog()
Definition: debug.cc:484
#define DBG_IMPORTANT
Definition: Stream.h:38
static int override_X
Definition: Stream.h:84
void ResyncDebugLog(FILE *newFile)
a hack for low-level file descriptor manipulations in ipcCreate()
Definition: debug.cc:515
a named FILE with very-early/late usage safety mechanisms
Definition: debug.cc:83
DebugFile()
Definition: debug.cc:86
static bool DidResetSections
Definition: debug.cc:80
bool shouldWrite(const DebugMessageHeader &) const final
Definition: debug.cc:1073
void fd_close(const int fd)
Definition: minimal.cc:21
static void LabelThisProcess(const char *const name, const std::optional< int > id=std::optional< int >())
optimization: formats ProcessLabel once for frequent debugs() reuse
Definition: debug.cc:370
void writeToStream(FILE &, const DebugMessageHeader &, const CompiledDebugMessageBody &)
Formats a validated debugs() record and writes it to the given FILE.
Definition: debug.cc:613
#define MAXPATHLEN
Definition: stdio.h:62
void saveMessage(const DebugMessageHeader &, const CompiledDebugMessageBody &)
stores the given early message (if possible) or forgets it (otherwise)
Definition: debug.cc:594
Logger & operator++()
Definition: debug.cc:196
Logger & operator*()
Definition: debug.cc:195
void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final
write the corresponding debugs() message into the channel
Definition: debug.cc:667
bool opened
whether openlog() was called
Definition: debug.cc:289
static void BanCacheLogUse()
Definition: debug.cc:1118
static Context * Current
deepest active context; nil outside debugs()
Definition: Stream.h:176
StderrChannel stderrChannel
Definition: debug.cc:321
#define BOOL
Definition: std-includes.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
FILE * file_
opened "real" file or nil; never stderr
Definition: debug.cc:104
Logger(DebugChannel &ch)
Definition: debug.cc:184
static auto Asserting_
Definition: debug.cc:1257
std::output_iterator_tag iterator_category
Definition: debug.cc:182
EarlyMessages earlyMessages
Definition: debug.cc:235
uint64_t DebugRecordCount
a counter related to the number of debugs() calls
Definition: debug.cc:35
static void StopCacheLogUse()
Definition: debug.cc:1132
char * name
Definition: debug.cc:99

 

Introduction

Documentation

Support

Miscellaneous