]>
Commit | Line | Data |
---|---|---|
c772f001 | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors |
c772f001 | 3 | * |
bbc27441 AJ |
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. | |
c772f001 | 7 | */ |
bbc27441 AJ |
8 | |
9 | /* DEBUG: section 00 Debug Routines */ | |
10 | ||
e1f7507e AJ |
11 | #ifndef SQUID_DEBUG_H |
12 | #define SQUID_DEBUG_H | |
c772f001 | 13 | |
ebaabe74 | 14 | #include "base/Here.h" |
ae72213d FC |
15 | // XXX should be mem/forward.h once it removes dependencies on typedefs.h |
16 | #include "mem/AllocatorProxy.h" | |
17 | ||
f95fe6ed | 18 | #include <iostream> |
a8d99c60 | 19 | #undef assert |
f95fe6ed | 20 | #include <sstream> |
bf8fe701 | 21 | #include <iomanip> |
27e059d4 | 22 | #if defined(assert) |
a8d99c60 | 23 | #undef assert |
24 | #endif | |
27e059d4 | 25 | |
a8d99c60 | 26 | #if PURIFY |
27 | #define assert(EX) ((void)0) | |
28 | #elif defined(NODEBUG) | |
29 | #define assert(EX) ((void)0) | |
30 | #elif STDC_HEADERS | |
31 | #define assert(EX) ((EX)?((void)0):xassert( # EX , __FILE__, __LINE__)) | |
32 | #else | |
33 | #define assert(EX) ((EX)?((void)0):xassert("EX", __FILE__, __LINE__)) | |
34 | #endif | |
f95fe6ed | 35 | |
62493678 AJ |
36 | /* context-based debugging, the actual type is subject to change */ |
37 | typedef int Ctx; | |
8a648e8d FC |
38 | Ctx ctx_enter(const char *descr); |
39 | void ctx_exit(Ctx ctx); | |
62493678 | 40 | |
e1f7507e AJ |
41 | /* defined debug section limits */ |
42 | #define MAX_DEBUG_SECTIONS 100 | |
43 | ||
feefade1 | 44 | /* defined names for Debug Levels */ |
f53969cc SM |
45 | #define DBG_CRITICAL 0 /**< critical messages always shown when they occur */ |
46 | #define DBG_IMPORTANT 1 /**< important messages always shown when their section is being checked */ | |
feefade1 | 47 | /* levels 2-8 are still being discussed amongst the developers */ |
f53969cc | 48 | #define DBG_DATA 9 /**< output is a large data dump only necessary for advanced debugging */ |
feefade1 | 49 | |
bbbea8ad AJ |
50 | #define DBG_PARSE_NOTE(x) (opt_parse_cfg_only?0:(x)) /**< output is always to be displayed on '-k parse' but at level-x normally. */ |
51 | ||
62e76326 | 52 | class Debug |
c772f001 | 53 | { |
62e76326 | 54 | |
c772f001 | 55 | public: |
014adac1 AR |
56 | /// meta-information for debugs() or a similar debugging call |
57 | class Context | |
58 | { | |
59 | public: | |
60 | Context(const int aSectionLevel, const int aLevel); | |
61 | ||
62 | int level; ///< minimum debugging level required by the debugs() call | |
63 | int sectionLevel; ///< maximum debugging level allowed during the call | |
64 | ||
65 | private: | |
66 | friend class Debug; | |
67 | void rewind(const int aSection, const int aLevel); | |
68 | void formatStream(); | |
69 | Context *upper; ///< previous or parent record in nested debugging calls | |
70 | std::ostringstream buf; ///< debugs() output sink | |
e863656d | 71 | bool forceAlert; ///< the current debugs() will be a syslog ALERT |
014adac1 AR |
72 | }; |
73 | ||
74 | /// whether debugging the given section and the given level produces output | |
75 | static bool Enabled(const int section, const int level) | |
76 | { | |
77 | return level <= Debug::Levels[section]; | |
78 | } | |
79 | ||
62493678 AJ |
80 | static char *debugOptions; |
81 | static char *cache_log; | |
82 | static int rotateNumber; | |
62e76326 | 83 | static int Levels[MAX_DEBUG_SECTIONS]; |
62493678 AJ |
84 | static int override_X; |
85 | static int log_stderr; | |
86 | static bool log_syslog; | |
87 | ||
d9e04dc7 | 88 | static void parseOptions(char const *); |
f95fe6ed | 89 | |
014adac1 AR |
90 | /// minimum level required by the current debugs() call |
91 | static int Level() { return Current ? Current->level : 1; } | |
92 | /// maximum level currently allowed | |
93 | static int SectionLevel() { return Current ? Current->sectionLevel : 1; } | |
26ac0430 | 94 | |
014adac1 AR |
95 | /// opens debugging context and returns output buffer |
96 | static std::ostringstream &Start(const int section, const int level); | |
97 | /// logs output buffer created in Start() and closes debugging context | |
98 | static void Finish(); | |
bfa09779 | 99 | |
e863656d CT |
100 | /// configures the active debugging context to write syslog ALERT |
101 | static void ForceAlert(); | |
ccfbe8f4 AR |
102 | |
103 | /// prefixes each grouped debugs() line after the first one in the group | |
104 | static std::ostream& Extra(std::ostream &os) { return os << "\n "; } | |
105 | ||
014adac1 AR |
106 | private: |
107 | static Context *Current; ///< deepest active context; nil outside debugs() | |
c772f001 | 108 | }; |
109 | ||
0c7e529e AR |
110 | /// cache.log FILE or, as the last resort, stderr stream; |
111 | /// may be nil during static initialization and destruction! | |
112 | FILE *DebugStream(); | |
113 | /// change-avoidance macro; new code should call DebugStream() instead | |
114 | #define debug_log DebugStream() | |
115 | ||
116 | /// start logging to stderr (instead of cache.log, if any) | |
117 | void StopUsingDebugLog(); | |
118 | ||
119 | /// a hack for low-level file descriptor manipulations in ipcCreate() | |
120 | void ResyncDebugLog(FILE *newDestination); | |
f76d2f97 | 121 | |
03714d23 FC |
122 | /* Debug stream |
123 | * | |
124 | * Unit tests can enable full debugging to stderr for one | |
125 | * debug section; to enable this, #define ENABLE_DEBUG_SECTION to the | |
126 | * section number before any header | |
127 | */ | |
f95fe6ed | 128 | #define debugs(SECTION, LEVEL, CONTENT) \ |
129 | do { \ | |
014adac1 AR |
130 | const int _dbg_level = (LEVEL); \ |
131 | if (Debug::Enabled((SECTION), _dbg_level)) { \ | |
132 | std::ostream &_dbo = Debug::Start((SECTION), _dbg_level); \ | |
133 | if (_dbg_level > DBG_IMPORTANT) { \ | |
134 | _dbo << (SECTION) << ',' << _dbg_level << "| " \ | |
ebaabe74 | 135 | << Here() << ": "; \ |
3304cfef | 136 | } \ |
bfd38d03 | 137 | _dbo << CONTENT; \ |
014adac1 | 138 | Debug::Finish(); \ |
f95fe6ed | 139 | } \ |
140 | } while (/*CONSTCOND*/ 0) | |
141 | ||
e863656d CT |
142 | /// Does not change the stream being manipulated. Exists for its side effect: |
143 | /// In a debugs() context, forces the message to become a syslog ALERT. | |
144 | /// Outside of debugs() context, has no effect and should not be used. | |
145 | std::ostream& ForceAlert(std::ostream& s); | |
146 | ||
fc9d2eb0 FC |
147 | /** stream manipulator which does nothing. |
148 | * \deprecated Do not add to new code, and remove when editing old code | |
def17b6a | 149 | * |
fc9d2eb0 FC |
150 | * Its purpose is to inactivate calls made following previous debugs() |
151 | * guidelines such as | |
23d6095a | 152 | * debugs(1,2, HERE << "some message"); |
fc9d2eb0 FC |
153 | * |
154 | * His former objective is now absorbed in the debugs call itself | |
def17b6a | 155 | */ |
fc9d2eb0 FC |
156 | inline std::ostream& |
157 | HERE(std::ostream& s) | |
158 | { | |
159 | return s; | |
160 | } | |
def17b6a | 161 | |
23d6095a AJ |
162 | /* |
163 | * MYNAME is for use at debug levels 0 and 1 where HERE is too messy. | |
164 | * | |
165 | * debugs(1,1, MYNAME << "WARNING: some message"); | |
166 | */ | |
167 | #ifdef __PRETTY_FUNCTION__ | |
168 | #define MYNAME __PRETTY_FUNCTION__ << " " | |
169 | #else | |
170 | #define MYNAME __FUNCTION__ << " " | |
171 | #endif | |
172 | ||
cc192b50 | 173 | /* some uint8_t do not like streaming control-chars (values 0-31, 127+) */ |
26ac0430 AJ |
174 | inline std::ostream& operator <<(std::ostream &os, const uint8_t d) |
175 | { | |
066c9540 | 176 | return (os << (int)d); |
177 | } | |
178 | ||
ec85ebda | 179 | /* Legacy debug function definitions */ |
8a648e8d | 180 | void _db_init(const char *logfile, const char *options); |
8a648e8d FC |
181 | void _db_set_syslog(const char *facility); |
182 | void _db_rotate_log(void); | |
96e03dd8 | 183 | |
be039a68 AR |
184 | /// Prints raw and/or non-terminated data safely, efficiently, and beautifully. |
185 | /// Allows raw data debugging in debugs() statements with low debugging levels | |
186 | /// by printing only if higher section debugging levels are configured: | |
187 | /// debugs(11, DBG_IMPORTANT, "always printed" << Raw(may be printed...)); | |
2113e038 A |
188 | class Raw |
189 | { | |
be039a68 AR |
190 | public: |
191 | Raw(const char *label, const char *data, const size_t size): | |
f5e17947 | 192 | level(-1), label_(label), data_(data), size_(size), useHex_(false), useGap_(true) {} |
be039a68 AR |
193 | |
194 | /// limit data printing to at least the given debugging level | |
195 | Raw &minLevel(const int aLevel) { level = aLevel; return *this; } | |
196 | ||
6821c276 CT |
197 | /// print data using two hex digits per byte (decoder: xxd -r -p) |
198 | Raw &hex() { useHex_ = true; return *this; } | |
199 | ||
f5e17947 CT |
200 | Raw &gap(bool useGap = true) { useGap_ = useGap; return *this; } |
201 | ||
be039a68 AR |
202 | /// If debugging is prohibited by the current debugs() or section level, |
203 | /// prints nothing. Otherwise, dumps data using one of these formats: | |
204 | /// " label[size]=data" if label was set and data size is positive | |
205 | /// " label[0]" if label was set and data size is zero | |
206 | /// " data" if label was not set and data size is positive | |
207 | /// "" (i.e., prints nothing) if label was not set and data size is zero | |
208 | std::ostream &print(std::ostream &os) const; | |
209 | ||
210 | /// Minimum section debugging level necessary for printing. By default, | |
211 | /// small strings are always printed while large strings are only printed | |
212 | /// if DBG_DATA debugging level is enabled. | |
213 | int level; | |
214 | ||
215 | private: | |
6821c276 CT |
216 | void printHex(std::ostream &os) const; |
217 | ||
be039a68 AR |
218 | const char *label_; ///< optional data name or ID; triggers size printing |
219 | const char *data_; ///< raw data to be printed | |
220 | size_t size_; ///< data length | |
6821c276 | 221 | bool useHex_; ///< whether hex() has been called |
f5e17947 | 222 | bool useGap_; ///< whether to print leading space if label is missing |
be039a68 AR |
223 | }; |
224 | ||
225 | inline | |
226 | std::ostream &operator <<(std::ostream &os, const Raw &raw) | |
227 | { | |
228 | return raw.print(os); | |
229 | } | |
230 | ||
cb171ead CT |
231 | /// debugs objects pointed by possibly nil pointers: label=object |
232 | template <class Pointer> | |
233 | class RawPointerT { | |
234 | public: | |
235 | RawPointerT(const char *aLabel, const Pointer &aPtr): | |
236 | label(aLabel), ptr(aPtr) {} | |
237 | const char *label; /// the name or description of the being-debugged object | |
238 | const Pointer &ptr; /// a possibly nil pointer to the being-debugged object | |
239 | }; | |
240 | ||
241 | /// convenience wrapper for creating RawPointerT<> objects | |
242 | template <class Pointer> | |
243 | inline RawPointerT<Pointer> | |
244 | RawPointer(const char *label, const Pointer &ptr) | |
245 | { | |
246 | return RawPointerT<Pointer>(label, ptr); | |
247 | } | |
248 | ||
249 | /// prints RawPointerT<>, dereferencing the raw pointer if possible | |
250 | template <class Pointer> | |
251 | inline std::ostream & | |
252 | operator <<(std::ostream &os, const RawPointerT<Pointer> &pd) | |
253 | { | |
254 | os << pd.label << '='; | |
255 | if (pd.ptr) | |
256 | return os << *pd.ptr; | |
257 | else | |
258 | return os << "[nil]"; | |
259 | } | |
260 | ||
653d9927 A |
261 | /// std::ostream manipulator to print integers as hex numbers prefixed by 0x |
262 | template <class Integer> | |
263 | class AsHex | |
264 | { | |
265 | public: | |
266 | explicit AsHex(const Integer n): raw(n) {} | |
267 | Integer raw; ///< the integer to print | |
268 | }; | |
269 | ||
270 | template <class Integer> | |
271 | inline std::ostream & | |
272 | operator <<(std::ostream &os, const AsHex<Integer> number) | |
273 | { | |
274 | const auto oldFlags = os.flags(); | |
275 | os << std::hex << std::showbase << number.raw; | |
276 | os.setf(oldFlags); | |
277 | return os; | |
278 | } | |
279 | ||
280 | /// a helper to ease AsHex object creation | |
281 | template <class Integer> | |
282 | inline AsHex<Integer> asHex(const Integer n) { return AsHex<Integer>(n); } | |
283 | ||
e1f7507e | 284 | #endif /* SQUID_DEBUG_H */ |
f53969cc | 285 |