2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 00 Debug Routines */
14 #include "SquidTime.h"
19 /* for shutting_down flag in xassert() */
22 char *Debug::debugOptions
= NULL
;
23 int Debug::override_X
= 0;
24 int Debug::log_stderr
= -1;
25 bool Debug::log_syslog
= false;
26 int Debug::Levels
[MAX_DEBUG_SECTIONS
];
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);
35 static int syslog_facility
= 0;
37 static void _db_print_syslog(const char *format
, va_list args
);
39 static void _db_print_stderr(const char *format
, va_list args
);
40 static void _db_print_file(const char *format
, va_list args
);
43 extern LPCRITICAL_SECTION dbg_mutex
;
44 typedef BOOL (WINAPI
* PFInitializeCriticalSectionAndSpinCount
) (LPCRITICAL_SECTION
, DWORD
);
47 /// a (FILE*, file name) pair that uses stderr FILE as the last resort
52 ~DebugFile() { clear(); }
53 DebugFile(DebugFile
&&) = delete; // no copying or moving of any kind
55 /// switches to the new pair, absorbing FILE and duping the name
56 void reset(FILE *newFile
, const char *newName
);
58 /// go back to the initial state
59 void clear() { reset(nullptr, nullptr); }
61 /// logging stream; the only method that uses stderr as the last resort
62 FILE *file() { return file_
? file_
: stderr
; }
67 friend void ResyncDebugLog(FILE *newFile
);
69 FILE *file_
= nullptr; ///< opened "real" file or nil; never stderr
72 /// configured cache.log file or stderr
73 /// safe during static initialization, even if it has not been constructed yet
74 static DebugFile TheLog
;
88 ResyncDebugLog(FILE *newFile
)
90 TheLog
.file_
= newFile
;
94 DebugFile::reset(FILE *newFile
, const char *newName
)
96 // callers must use nullptr instead of the used-as-the-last-resort stderr
97 assert(newFile
!= stderr
|| !stderr
);
101 file_
= newFile
; // may be nil
104 name
= newName
? xstrdup(newName
) : nullptr;
106 // all open files must have a name
107 // all cleared files must not have a name
108 assert(!file_
== !name
);
112 _db_print(const char *format
,...)
121 /* Multiple WIN32 threads may call this simultaneously */
124 HMODULE krnl_lib
= GetModuleHandle("Kernel32");
125 PFInitializeCriticalSectionAndSpinCount InitializeCriticalSectionAndSpinCount
= NULL
;
128 InitializeCriticalSectionAndSpinCount
=
129 (PFInitializeCriticalSectionAndSpinCount
) GetProcAddress(krnl_lib
,
130 "InitializeCriticalSectionAndSpinCount");
132 dbg_mutex
= static_cast<CRITICAL_SECTION
*>(xcalloc(1, sizeof(CRITICAL_SECTION
)));
134 if (InitializeCriticalSectionAndSpinCount
) {
135 /* let multiprocessor systems EnterCriticalSection() fast */
137 if (!InitializeCriticalSectionAndSpinCount(dbg_mutex
, 4000)) {
139 fprintf(debug_log
, "FATAL: _db_print: can't initialize critical section\n");
143 fprintf(stderr
, "FATAL: _db_print: can't initialize critical section\n");
146 InitializeCriticalSection(dbg_mutex
);
150 EnterCriticalSection(dbg_mutex
);
153 /* give a chance to context-based debugging to print current context */
157 va_start(args1
, format
);
158 va_start(args2
, format
);
159 va_start(args3
, format
);
161 snprintf(f
, BUFSIZ
, "%s%s| %s",
166 _db_print_file(f
, args1
);
167 _db_print_stderr(f
, args2
);
170 _db_print_syslog(format
, args3
);
174 LeaveCriticalSection(dbg_mutex
);
183 _db_print_file(const char *format
, va_list args
)
185 if (debug_log
== NULL
)
188 /* give a chance to context-based debugging to print current context */
192 vfprintf(debug_log
, format
, args
);
197 _db_print_stderr(const char *format
, va_list args
)
199 if (Debug::log_stderr
< Debug::Level())
202 if (debug_log
== stderr
)
205 vfprintf(stderr
, format
, args
);
210 _db_print_syslog(const char *format
, va_list args
)
212 /* level 0,1 go to syslog */
214 if (Debug::Level() > 1)
217 if (!Debug::log_syslog
)
223 vsnprintf(tmpbuf
, BUFSIZ
, format
, args
);
225 tmpbuf
[BUFSIZ
- 1] = '\0';
227 syslog(Debug::Level() == 0 ? LOG_WARNING
: LOG_NOTICE
, "%s", tmpbuf
);
229 #endif /* HAVE_SYSLOG */
232 debugArg(const char *arg
)
238 if (!strncasecmp(arg
, "rotate=", 7)) {
240 Debug::rotateNumber
= atoi(arg
);
242 } else if (!strncasecmp(arg
, "ALL", 3)) {
247 while (*arg
&& *arg
++ != ',');
253 if (s
>= MAX_DEBUG_SECTIONS
)
254 s
= MAX_DEBUG_SECTIONS
-1;
263 Debug::Levels
[s
] = l
;
267 for (i
= 0; i
< MAX_DEBUG_SECTIONS
; ++i
)
268 Debug::Levels
[i
] = l
;
272 debugOpenLog(const char *logfile
)
274 if (logfile
== NULL
) {
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;
284 logfilename
= logfile
;
286 if (auto log
= fopen(logfilename
, "a+")) {
288 setmode(fileno(log
), O_TEXT
);
290 TheLog
.reset(log
, logfilename
);
292 fprintf(stderr
, "WARNING: Cannot write log file: %s\n", logfile
);
294 fprintf(stderr
, " messages will be sent to 'stderr'.\n");
303 static struct syslog_facility_name
{
308 syslog_facility_names
[] = {
317 "authpriv", LOG_AUTHPRIV
418 _db_set_syslog(const char *facility
)
420 Debug::log_syslog
= true;
425 syslog_facility
= LOG_DAEMON
;
428 syslog_facility
= LOG_LOCAL4
;
429 #endif /* LOG_DAEMON */
433 struct syslog_facility_name
*n
;
435 for (n
= syslog_facility_names
; n
->name
; ++n
) {
436 if (strcmp(n
->name
, facility
) == 0) {
437 syslog_facility
= n
->facility
;
442 fprintf(stderr
, "unknown syslog facility '%s'\n", facility
);
448 fprintf(stderr
, "syslog facility type not supported on your system\n");
450 #endif /* LOG_LOCAL4 */
456 Debug::parseOptions(char const *options
)
463 debugs(0, 9, "command-line -X overrides: " << options
);
467 for (i
= 0; i
< MAX_DEBUG_SECTIONS
; ++i
)
468 Debug::Levels
[i
] = 0;
471 p
= xstrdup(options
);
473 for (s
= strtok(p
, w_space
); s
; s
= strtok(NULL
, w_space
))
481 _db_init(const char *logfile
, const char *options
)
483 Debug::parseOptions(options
);
485 debugOpenLog(logfile
);
487 #if HAVE_SYSLOG && defined(LOG_LOCAL4)
489 if (Debug::log_syslog
)
490 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, syslog_facility
);
492 #endif /* HAVE_SYSLOG */
494 /* Pre-Init TZ env, see bug #2656 */
506 if (stat(TheLog
.name
, &sb
) == 0)
507 if (S_ISREG(sb
.st_mode
) == 0)
511 char from
[MAXPATHLEN
];
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.
522 /* Rotate numbers 0 through N up one */
523 for (int i
= Debug::rotateNumber
; i
> 1;) {
525 snprintf(from
, MAXPATHLEN
, "%s.%d", TheLog
.name
, i
- 1);
526 snprintf(to
, MAXPATHLEN
, "%s.%d", TheLog
.name
, i
);
532 if (rename(from
, to
) == -1) {
533 const auto saved_errno
= errno
;
534 debugs(0, DBG_IMPORTANT
, "log rotation failed: " << xstrerr(saved_errno
));
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);
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
));
550 TheLog
.clear(); // Windows cannot rename() open files
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
));
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
);
569 time_t t
= getCurrentTime();
572 static char buf
[128];
573 static time_t last_t
= 0;
575 if (Debug::Level() > 1) {
578 strftime(buf2
, 127, "%Y/%m/%d %H:%M:%S", tm
);
580 snprintf(buf
, 127, "%s.%03d", buf2
, (int) current_time
.tv_usec
/ 1000);
582 } else if (t
!= last_t
) {
584 strftime(buf
, 127, "%Y/%m/%d %H:%M:%S", tm
);
595 if (KidIdentifier
!= 0) {
597 if (!*buf
) // optimization: fill only once after KidIdentifier is set
598 snprintf(buf
, sizeof(buf
), " kid%d", KidIdentifier
);
606 xassert(const char *msg
, const char *file
, int line
)
608 debugs(0, DBG_CRITICAL
, "assertion failed: " << file
<< ":" << line
<< ": \"" << msg
<< "\"");
615 * Context-based Debugging
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.
626 * To solve this potential problem, use the following approach:
629 * top_level_foo(const char *url)
631 * // define current context
632 * // note: we stack but do not dup ctx descriptions!
633 * Ctx ctx = ctx_enter(url);
635 * // go down; middle_level_bar will eventually call bottom_level_boo
636 * middle_level_bar(method, protocol);
638 * // exit, clean after yourself
643 * bottom_level_boo(int status, void *data)
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);
652 * Current implementation is extremely simple but still very handy. It has a
653 * negligible overhead (descriptions are not duplicated).
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.
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.
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
671 * i) locate debugging message,
672 * ii) locate current context by going _upstream_ in your log file,
679 * decide if we want to dup() descriptions (adds overhead) but allows to
680 * add printf()-style interface
685 * descriptions for contexts over CTX_MAX_LEVEL limit are ignored, you probably
686 * have a bug if your nesting goes that deep.
689 #define CTX_MAX_LEVEL 255
692 * produce a warning when nesting reaches this level and then double
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
);
708 ctx_enter(const char *descr
)
712 if (Ctx_Current_Level
<= CTX_MAX_LEVEL
)
713 Ctx_Descrs
[Ctx_Current_Level
] = descr
;
715 if (Ctx_Current_Level
== Ctx_Warn_Level
) {
716 debugs(0, DBG_CRITICAL
, "# ctx: suspiciously deep (" << Ctx_Warn_Level
<< ") nesting:");
720 return Ctx_Current_Level
;
727 Ctx_Current_Level
= (ctx
>= 0) ? ctx
- 1 : -1;
729 if (Ctx_Valid_Level
> Ctx_Current_Level
)
730 Ctx_Valid_Level
= Ctx_Current_Level
;
734 * the idea id to print each context description at most once but provide enough
735 * info for deducing the current execution stack
740 /* lock so _db_print will not call us recursively */
742 /* ok, user saw [0,Ctx_Reported_Level] descriptions */
743 /* first inform about entries popped since user saw them */
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);
750 _db_print("ctx: exit level %2d\n", Ctx_Reported_Level
);
752 Ctx_Reported_Level
= Ctx_Valid_Level
;
755 /* report new contexts that were pushed since last report */
756 while (Ctx_Reported_Level
< Ctx_Current_Level
) {
757 ++Ctx_Reported_Level
;
759 _db_print("ctx: enter level %2d: '%s'\n", Ctx_Reported_Level
,
760 ctx_get_descr(Ctx_Reported_Level
));
767 /* checks for nulls and overflows */
769 ctx_get_descr(Ctx ctx
)
771 if (ctx
< 0 || ctx
> CTX_MAX_LEVEL
)
774 return Ctx_Descrs
[ctx
] ? Ctx_Descrs
[ctx
] : "<null>";
777 Debug::Context
*Debug::Current
= nullptr;
779 Debug::Context::Context(const int aSection
, const int aLevel
):
781 sectionLevel(Levels
[aSection
]),
787 /// Optimization: avoids new Context creation for every debugs().
789 Debug::Context::rewind(const int aSection
, const int aLevel
)
792 sectionLevel
= Levels
[aSection
];
793 assert(upper
== Current
);
795 buf
.str(std::string());
797 // debugs() users are supposed to preserve format, but
798 // some do not, so we have to waste cycles resetting it for all.
802 /// configures default formatting for the debugging stream
804 Debug::Context::formatStream()
806 const static std::ostringstream cleanStream
;
807 buf
.flags(cleanStream
.flags() | std::ios::fixed
);
808 buf
.width(cleanStream
.width());
811 // If this is not enough, use copyfmt(cleanStream) which is ~10% slower.
815 Debug::Start(const int section
, const int level
)
817 Context
*future
= nullptr;
819 // prepare future context
821 // all reentrant debugs() calls get here; create a dedicated context
822 future
= new Context(section
, level
);
824 // Optimization: Nearly all debugs() calls get here; avoid allocations
825 static Context
*topContext
= new Context(1, 1);
826 topContext
->rewind(section
, level
);
838 // TODO: Optimize to remove at least one extra copy.
839 _db_print("%s\n", Current
->buf
.str().c_str());
841 Context
*past
= Current
;
842 Current
= past
->upper
;
845 // else it was a static topContext from Debug::Start()
851 // XXX: This must be kept in sync with the actual debug.cc location
852 const char *ThisFileNameTail
= "src/debug.cc";
854 const char *file
=__FILE__
;
856 // Disable heuristic if it does not work.
857 if (!strstr(file
, ThisFileNameTail
))
860 return strlen(file
)-strlen(ThisFileNameTail
);
864 SkipBuildPrefix(const char* path
)
866 static const size_t BuildPrefixLength
= BuildPrefixInit();
868 return path
+BuildPrefixLength
;
871 /// print data bytes using hex notation
873 Raw::printHex(std::ostream
&os
) const
875 const auto savedFill
= os
.fill('0');
876 const auto savedFlags
= os
.flags(); // std::ios_base::fmtflags
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
);
885 Raw::print(std::ostream
&os
) const
888 os
<< ' ' << label_
<< '[' << size_
<< ']';
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_
? '=' : ' ');
902 os
.write(data_
, size_
);