Squid Web Cache v8/master
Loading...
Searching...
No Matches
debug.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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
27char *Debug::debugOptions = nullptr;
28int Debug::override_X = 0;
29bool Debug::log_syslog = false;
31char *Debug::cache_log = nullptr;
32int Debug::rotateNumber = -1;
33
35using DebugRecordCount = uint64_t;
36
37class DebugModule;
38
40static DebugModule *Module_ = nullptr;
41
45static std::optional<int> ExplicitStderrLevel;
46
53static int DefaultStderrLevel = -1;
54
56static constexpr int EarlyMessagesLevel = DBG_IMPORTANT;
57
59static std::string ProcessLabel;
60
61static const char *debugLogTime(const timeval &);
62
63#if HAVE_SYSLOG
64#ifdef LOG_LOCAL4
65static int syslog_facility = 0;
66#endif
67#endif
68
69#if _SQUID_WINDOWS_
70extern LPCRITICAL_SECTION dbg_mutex;
71typedef BOOL (WINAPI * PFInitializeCriticalSectionAndSpinCount) (LPCRITICAL_SECTION, DWORD);
72#endif
73
74static void ResetSections(const int level = DBG_IMPORTANT);
75
80static bool DidResetSections = false;
81
84{
85public:
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
101private:
102 friend void ResyncDebugLog(FILE *newFile);
103
104 FILE *file_ = nullptr;
105};
106
109{
110public:
111 DebugMessageHeader(const DebugRecordCount aRecordNumber, const Debug::Context &);
112
114 struct timeval timestamp;
116 int level;
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!
126using CompiledDebugMessageBody = std::string;
127
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.
145using CompiledDebugMessages = std::deque<CompiledDebugMessage>;
146
149{
150public:
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)
158
160 bool collectingEarlyMessages() const { return bool(earlyMessages); }
161
164
168
171 void log(const DebugMessageHeader &, const CompiledDebugMessageBody &);
172
173protected:
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
223protected:
224 const char * const name = nullptr;
225
228
231
236};
237
240{
241public:
242 CacheLogChannel(): DebugChannel("cache_log") {}
243
244protected:
245 /* DebugChannel API */
246 bool shouldWrite(const DebugMessageHeader &) const final;
247 void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final;
248};
249
252{
253public:
255
258
261
263 bool enabled(const int messageDebugLevel) const;
264
265protected:
266 /* DebugChannel API */
267 bool shouldWrite(const DebugMessageHeader &) const final;
268 void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final;
269
270private:
273};
274
277{
278public:
280
281 void markOpened() { opened = true; }
282
283protected:
284 /* DebugChannel API */
285 bool shouldWrite(const DebugMessageHeader &) const final;
286 void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final;
287
288private:
289 bool opened = false;
290};
291
297{
298public:
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
319public:
323};
324
330{
331public:
334
336 static bool Busy() { return LoggingConcurrencyLevel; }
337
338private:
341};
342
344
348
353
354FILE *
356 return TheLog.file() ? TheLog.file() : stderr;
357}
358
360static void
361ResetSections(const int level)
362{
363 DidResetSections = true;
364 for (auto &sectionLevel: Debug::Levels)
365 sectionLevel = level;
366}
367
369static void
370LabelThisProcess(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
383void
384Debug::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
399
400 SettleStderr();
401 SettleSyslog();
402
403 debugs(84, 2, "starting " << name << " with PID " << getpid());
404}
405
406void
407Debug::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
423
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)
444}
445
446void
448{
449 cacheLogChannel.log(header, body);
450 stderrChannel.log(header, body);
451 syslogChannel.log(header, body);
452}
453
454void
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.
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
483void
485{
486 assert(TheLog.file());
487 stderrChannel.stopCoveringForCacheLog(); // in case it was covering
488 cacheLogChannel.stopEarlyMessageCollection(); // in case it was collecting
489}
490
491void
497
499static
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
514void
515ResyncDebugLog(FILE *newFile)
516{
517 TheLog.file_ = newFile;
518}
519
520/* DebugChannel */
521
522DebugChannel::DebugChannel(const char * const aName):
523 name(aName),
524 earlyMessages(new CompiledDebugMessages())
525{
526}
527
528void
530{
531 if (earlyMessages)
532 StopSavingAndLog(*this);
533 // else already stopped
534}
535
536void
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
553void
555{
556 auto &module = Module();
557 (void)module.cacheLogChannel.releaseEarlyMessages();
558 (void)module.stderrChannel.releaseEarlyMessages();
559 (void)module.syslogChannel.releaseEarlyMessages();
560}
561
562void
567
568void
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
593void
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
612void
613DebugChannel::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
622void
628
629/* CacheLogChannel */
630
631bool
633{
634 return TheLog.file();
635}
636
637void
639{
640 writeToStream(*TheLog.file(), header, body);
641 fflush(TheLog.file());
642}
643
644/* StderrChannel */
645
646bool
647StderrChannel::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
660bool
662{
663 return enabled(header.level);
664}
665
666void
668{
669 writeToStream(*stderr, header, body);
670}
671
672void
674{
676 return;
677 coveringForCacheLog = true;
678
679 StopSavingAndLog(*this, &cacheLogChannel);
680}
681
682void
684{
686 return;
687
688 coveringForCacheLog = false;
689 debugs(0, DBG_IMPORTANT, "Resuming logging to cache_log");
690}
691
692void
694{
695 if (DefaultStderrLevel < maxDefault)
696 DefaultStderrLevel = maxDefault; // may set or increase
697 // else: somebody has already requested a more permissive maximum
698}
699
700void
701Debug::ResetStderrLevel(const int maxLevel)
702{
703 ExplicitStderrLevel = maxLevel; // may set, increase, or decrease
704}
705
706void
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
726bool
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
754void
755DebugFile::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
780void
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
825static void
826debugArg(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
863static void
864debugOpenLog(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);
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
896static struct syslog_facility_name {
897 const char *name;
898 int facility;
899}
900
901syslog_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
1010static 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
1048static int
1049SyslogPriority(const DebugMessageHeader &header)
1050{
1051 return header.forceAlert ? LOG_ALERT :
1052 (header.level == 0 ? LOG_WARNING : LOG_NOTICE);
1053}
1054
1055void
1057{
1058 syslog(SyslogPriority(header), "%s", body.c_str());
1059 noteWritten(header);
1060}
1061
1062#else
1063
1064void
1066{
1067 assert(!"unreachable code because opened, shouldWrite() are always false");
1068}
1069
1070#endif /* HAVE_SYSLOG */
1071
1072bool
1074{
1075 if (!opened)
1076 return false;
1077
1079 return header.forceAlert || header.level <= DBG_IMPORTANT;
1080}
1081
1082void
1083Debug::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
1094void
1095Debug::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
1117void
1123
1124void
1130
1131void
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
1144void
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
1159void
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
1226static const char *
1227debugLogTime(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
1257static auto Asserting_ = false;
1258
1259void
1260xassert(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
1276
1277Debug::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{
1286}
1287
1289void
1290Debug::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
1304void
1305Debug::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
1315std::ostream &
1316Debug::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
1326void
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
1341std::ostringstream &
1342Debug::Start(const int section, const int level)
1343{
1344 Context *future = nullptr;
1345
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
1365void
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
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
1402void
1404{
1405 // the ForceAlert(ostream) manipulator should only be used inside debugs()
1406 if (Current)
1407 Current->forceAlert = true;
1408}
1409
1410std::ostream&
1411ForceAlert(std::ostream& s)
1412{
1414 return s;
1415}
1416
std::ostream & CurrentCodeContextDetail(std::ostream &os)
void log(char *format,...)
#define assert(EX)
Definition assert.h:17
DebugChannel managing messages destined for the configured cache_log file.
Definition debug.cc:240
void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final
write the corresponding debugs() message into the channel
Definition debug.cc:638
bool shouldWrite(const DebugMessageHeader &) const final
Definition debug.cc:632
a fully processed debugs(), ready to be logged
Definition debug.cc:130
CompiledDebugMessage(const Header &, const Body &)
Definition debug.cc:746
CompiledDebugMessageBody Body
Definition debug.cc:133
Header header
debugs() meta-information; reflected in log line prefix
Definition debug.cc:137
Body body
the log line after the prefix (without the newline)
Definition debug.cc:138
output iterator for writing CompiledDebugMessages to a given channel
Definition debug.cc:176
Logger(DebugChannel &ch)
Definition debug.cc:184
std::reference_wrapper< DebugChannel > channel
output destination
Definition debug.cc:201
Logger & operator++()
Definition debug.cc:196
Logger & operator=(const CompiledDebugMessage &message)
Definition debug.cc:186
Logger & operator++(int)
Definition debug.cc:197
std::output_iterator_tag iterator_category
Definition debug.cc:182
Logger & operator*()
Definition debug.cc:195
a receiver of debugs() messages (e.g., stderr or cache.log)
Definition debug.cc:149
DebugChannel(DebugChannel &&)=delete
DebugRecordCount written
the number of messages sent to the underlying channel so far
Definition debug.cc:227
void saveMessage(const DebugMessageHeader &, const CompiledDebugMessageBody &)
stores the given early message (if possible) or forgets it (otherwise)
Definition debug.cc:594
static void StopSavingAndLog(DebugChannel &, DebugChannel *=nullptr)
stop saving and log() any "early" messages, in recordNumber order
Definition debug.cc:569
void noteWritten(const DebugMessageHeader &)
reacts to a written a debugs() message
Definition debug.cc:623
void writeToStream(FILE &, const DebugMessageHeader &, const CompiledDebugMessageBody &)
Formats a validated debugs() record and writes it to the given FILE.
Definition debug.cc:613
virtual ~DebugChannel()=default
EarlyMessages releaseEarlyMessages()
Definition debug.cc:167
void log(const DebugMessageHeader &, const CompiledDebugMessageBody &)
Definition debug.cc:537
std::unique_ptr< CompiledDebugMessages > EarlyMessages
Definition debug.cc:151
void stopEarlyMessageCollection()
end early message buffering, logging any saved messages
Definition debug.cc:529
bool collectingEarlyMessages() const
whether we are still expecting (and buffering) early messages
Definition debug.cc:160
DebugChannel(const char *aName)
Definition debug.cc:522
const char *const name
unique channel label for debugging
Definition debug.cc:224
virtual void write(const DebugMessageHeader &, const CompiledDebugMessageBody &)=0
write the corresponding debugs() message into the channel
EarlyMessages earlyMessages
Definition debug.cc:235
DebugRecordCount lastWrittenRecordNumber
DebugMessageHeader::recordNumber of the last message we wrote.
Definition debug.cc:230
virtual bool shouldWrite(const DebugMessageHeader &) const =0
a named FILE with very-early/late usage safety mechanisms
Definition debug.cc:84
friend void ResyncDebugLog(FILE *newFile)
a hack for low-level file descriptor manipulations in ipcCreate()
Definition debug.cc:515
char * name
Definition debug.cc:99
FILE * file()
an opened cache_log stream or nil
Definition debug.cc:97
~DebugFile()
Definition debug.cc:87
DebugFile(DebugFile &&)=delete
void clear()
go back to the initial state
Definition debug.cc:94
FILE * file_
opened "real" file or nil; never stderr
Definition debug.cc:104
void reset(FILE *newFile, const char *newName)
switches to the new pair, absorbing FILE and duping the name
Definition debug.cc:755
DebugFile()
Definition debug.cc:86
meta-information of a Finish()ed debugs() message
Definition debug.cc:109
DebugRecordCount recordNumber
LogMessage() calls before this message.
Definition debug.cc:113
int section
debugs() section
Definition debug.cc:115
int level
debugs() level
Definition debug.cc:116
bool forceAlert
debugs() forceAlert flag
Definition debug.cc:117
DebugMessageHeader(const DebugRecordCount aRecordNumber, const Debug::Context &)
Definition debug.cc:734
struct timeval timestamp
approximate debugs() call time
Definition debug.cc:114
~DebugModule()=delete
DebugModule()
Definition debug.cc:435
SyslogChannel syslogChannel
Definition debug.cc:322
CacheLogChannel cacheLogChannel
Definition debug.cc:320
void banCacheLogUse()
Definition debug.cc:492
StderrChannel stderrChannel
Definition debug.cc:321
void log(const DebugMessageHeader &, const CompiledDebugMessageBody &)
Definition debug.cc:447
void useCacheLog()
Definition debug.cc:484
void prepareToDie()
Definition debug.cc:455
meta-information for debugs() or a similar debugging call
Definition Stream.h:52
bool waitingForIdle
Definition Stream.h:71
Context * upper
previous or parent record in nested debugging calls
Definition Stream.h:65
std::ostringstream buf
debugs() output sink
Definition Stream.h:66
int level
minimum debugging level required by the debugs() call
Definition Stream.h:57
bool forceAlert
the current debugs() will be a syslog ALERT
Definition Stream.h:67
void rewind(const int aSection, const int aLevel)
Optimization: avoids new Context creation for every debugs().
Definition debug.cc:1290
Context(const int aSectionLevel, const int aLevel)
Definition debug.cc:1277
static void ResetStderrLevel(int maxLevel)
Definition debug.cc:701
static bool StderrEnabled()
Definition debug.cc:727
static bool log_syslog
Definition Stream.h:85
static void parseOptions(char const *)
Definition debug.cc:1095
static void PrepareToDie()
Definition debug.cc:563
static void ForgetSaved()
silently erases saved early debugs() messages (if any)
Definition debug.cc:554
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
Definition Stream.h:75
static Context * Current
deepest active context; nil outside debugs()
Definition Stream.h:176
static std::ostream & Extra(std::ostream &)
Definition debug.cc:1316
static void NameThisKid(int kidIdentifier)
Definition debug.cc:407
static void LogMessage(const Context &)
broadcasts debugs() message to the logging channels
Definition debug.cc:781
static int override_X
Definition Stream.h:84
static void SettleSyslog()
Definition debug.cc:1145
static int Levels[MAX_DEBUG_SECTIONS]
Definition Stream.h:83
static void Finish()
logs output buffer created in Start() and closes debugging context
Definition debug.cc:1366
static void NameThisHelper(const char *name)
Definition debug.cc:384
static char * debugOptions
Definition Stream.h:80
static void UseCacheLog()
Definition debug.cc:1125
static char * cache_log
Definition Stream.h:81
static void FormatStream(std::ostream &)
configures default formatting for the debugging stream
Definition debug.cc:1305
static std::ostringstream & Start(const int section, const int level)
opens debugging context and returns output buffer
Definition debug.cc:1342
static void BanCacheLogUse()
Definition debug.cc:1118
static void ConfigureSyslog(const char *facility)
enables logging to syslog (using the specified facility, when not nil)
Definition debug.cc:1083
static void StopCacheLogUse()
Definition debug.cc:1132
static int Level()
minimum level required by the current debugs() call
Definition Stream.h:100
static int rotateNumber
Definition Stream.h:82
static void EnsureDefaultStderrLevel(int maxDefault)
Definition debug.cc:693
static void SettleStderr()
Definition debug.cc:707
static void LogWaitingForIdle()
Logs messages of Finish()ed debugs() calls that were queued earlier.
Definition debug.cc:1327
static void ForceAlert()
configures the active debugging context to write syslog ALERT
Definition debug.cc:1403
static bool Busy()
whether new debugs() messages must be queued
Definition debug.cc:336
static size_t LoggingConcurrencyLevel
the current number of protected callers
Definition debug.cc:340
DebugChannel managing messages destined for "standard error stream" (stderr)
Definition debug.cc:252
bool shouldWrite(const DebugMessageHeader &) const final
Definition debug.cc:661
bool enabled(const int messageDebugLevel) const
Definition debug.cc:647
void takeOver(CacheLogChannel &)
start to take care of past/saved and future cacheLovirtual gChannel messages
Definition debug.cc:673
void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final
write the corresponding debugs() message into the channel
Definition debug.cc:667
void stopCoveringForCacheLog()
stop providing a cache_log replacement (if we were providing it)
Definition debug.cc:683
bool coveringForCacheLog
whether we are the last resort for logging debugs() messages
Definition debug.cc:272
syslog DebugChannel
Definition debug.cc:277
bool shouldWrite(const DebugMessageHeader &) const final
Definition debug.cc:1073
bool opened
whether openlog() was called
Definition debug.cc:289
void write(const DebugMessageHeader &, const CompiledDebugMessageBody &) final
write the corresponding debugs() message into the channel
Definition debug.cc:1065
void markOpened()
Definition debug.cc:281
void fd_open(const int fd, unsigned int, const char *description)
Definition minimal.cc:15
void fd_close(const int fd)
Definition minimal.cc:21
void commSetCloseOnExec(int fd)
Definition comm.cc:1105
#define w_space
#define DBG_DATA
Definition Stream.h:40
#define assert(EX)
Definition Stream.h:30
#define MAX_DEBUG_SECTIONS
Definition Stream.h:34
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define DBG_CRITICAL
Definition Stream.h:37
#define O_TEXT
Definition defines.h:131
@ FD_LOG
Definition enums.h:14
void fatalf(const char *fmt,...)
Definition fatal.cc:68
#define xfree
#define xstrdup
static char last
Definition parse.c:451
FILE * DebugStream()
Definition debug.cc:355
void ResyncDebugLog(FILE *newFile)
a hack for low-level file descriptor manipulations in ipcCreate()
Definition debug.cc:515
static DebugModule & Module()
safe access to the debugging module
Definition debug.cc:501
static std::optional< int > ExplicitStderrLevel
Definition debug.cc:45
std::deque< CompiledDebugMessage > CompiledDebugMessages
debugs() messages captured in LogMessage() call order
Definition debug.cc:145
uint64_t DebugRecordCount
a counter related to the number of debugs() calls
Definition debug.cc:35
static DebugModule * Module_
Debugging module singleton.
Definition debug.cc:40
static auto Asserting_
Definition debug.cc:1257
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
static Debug::Context * WaitingForIdle
Definition debug.cc:347
static const char * debugLogTime(const timeval &)
Definition debug.cc:1227
static void debugOpenLog(const char *logfile)
Definition debug.cc:864
static int DefaultStderrLevel
Definition debug.cc:53
void _db_rotate_log(void)
Definition debug.cc:1160
static std::string ProcessLabel
pre-formatted name of the current process for debugs() messages (or empty)
Definition debug.cc:59
void xassert(const char *msg, const char *file, int line)
Definition debug.cc:1260
static bool DidResetSections
Definition debug.cc:80
static DebugFile TheLog
Definition debug.cc:352
static void ResetSections(const int level=DBG_IMPORTANT)
used for the side effect: fills Debug::Levels with the given level
Definition debug.cc:361
static constexpr int EarlyMessagesLevel
early debugs() with higher level are not buffered and, hence, may be lost
Definition debug.cc:56
std::string CompiledDebugMessageBody
The processed "content" (i.e. the last parameter) part of a debugs() call.
Definition debug.cc:126
static void debugArg(const char *arg)
Definition debug.cc:826
#define MAXPATHLEN
Definition stdio.h:62
time_t getCurrentTime() STUB_RETVAL(0) int tvSubUsec(struct timeval
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition gadgets.cc:18
#define APP_SHORTNAME
Definition version.h:22
SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex
void * xcalloc(size_t n, size_t sz)
Definition xalloc.cc:71
const char * xstrerr(int error)
Definition xstrerror.cc:83