]> git.ipfire.org Git - thirdparty/squid.git/blob - src/Debug.h
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / Debug.h
1 /*
2 * Copyright (C) 1996-2020 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 #ifndef SQUID_DEBUG_H
12 #define SQUID_DEBUG_H
13
14 #include "base/Here.h"
15 // XXX should be mem/forward.h once it removes dependencies on typedefs.h
16 #include "mem/AllocatorProxy.h"
17
18 #include <iostream>
19 #undef assert
20 #include <sstream>
21 #include <iomanip>
22 #if defined(assert)
23 #undef assert
24 #endif
25
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
35
36 /* context-based debugging, the actual type is subject to change */
37 typedef int Ctx;
38 Ctx ctx_enter(const char *descr);
39 void ctx_exit(Ctx ctx);
40
41 /* defined debug section limits */
42 #define MAX_DEBUG_SECTIONS 100
43
44 /* defined names for Debug Levels */
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 */
47 /* levels 2-8 are still being discussed amongst the developers */
48 #define DBG_DATA 9 /**< output is a large data dump only necessary for advanced debugging */
49
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
52 class Debug
53 {
54
55 public:
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
71 bool forceAlert; ///< the current debugs() will be a syslog ALERT
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
80 static char *debugOptions;
81 static char *cache_log;
82 static int rotateNumber;
83 static int Levels[MAX_DEBUG_SECTIONS];
84 static int override_X;
85 static int log_stderr;
86 static bool log_syslog;
87
88 static void parseOptions(char const *);
89
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; }
94
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();
99
100 /// configures the active debugging context to write syslog ALERT
101 static void ForceAlert();
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
106 private:
107 static Context *Current; ///< deepest active context; nil outside debugs()
108 };
109
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);
121
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 */
128 #define debugs(SECTION, LEVEL, CONTENT) \
129 do { \
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 << "| " \
135 << Here() << ": "; \
136 } \
137 _dbo << CONTENT; \
138 Debug::Finish(); \
139 } \
140 } while (/*CONSTCOND*/ 0)
141
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
147 /** stream manipulator which does nothing.
148 * \deprecated Do not add to new code, and remove when editing old code
149 *
150 * Its purpose is to inactivate calls made following previous debugs()
151 * guidelines such as
152 * debugs(1,2, HERE << "some message");
153 *
154 * His former objective is now absorbed in the debugs call itself
155 */
156 inline std::ostream&
157 HERE(std::ostream& s)
158 {
159 return s;
160 }
161
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
173 /* some uint8_t do not like streaming control-chars (values 0-31, 127+) */
174 inline std::ostream& operator <<(std::ostream &os, const uint8_t d)
175 {
176 return (os << (int)d);
177 }
178
179 /* Legacy debug function definitions */
180 void _db_init(const char *logfile, const char *options);
181 void _db_set_syslog(const char *facility);
182 void _db_rotate_log(void);
183
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...));
188 class Raw
189 {
190 public:
191 Raw(const char *label, const char *data, const size_t size):
192 level(-1), label_(label), data_(data), size_(size), useHex_(false), useGap_(true) {}
193
194 /// limit data printing to at least the given debugging level
195 Raw &minLevel(const int aLevel) { level = aLevel; return *this; }
196
197 /// print data using two hex digits per byte (decoder: xxd -r -p)
198 Raw &hex() { useHex_ = true; return *this; }
199
200 Raw &gap(bool useGap = true) { useGap_ = useGap; return *this; }
201
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:
216 void printHex(std::ostream &os) const;
217
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
221 bool useHex_; ///< whether hex() has been called
222 bool useGap_; ///< whether to print leading space if label is missing
223 };
224
225 inline
226 std::ostream &operator <<(std::ostream &os, const Raw &raw)
227 {
228 return raw.print(os);
229 }
230
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
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
284 #endif /* SQUID_DEBUG_H */
285