/src/wxwidgets/include/wx/log.h
Line | Count | Source (jump to first uncovered line) |
1 | | ///////////////////////////////////////////////////////////////////////////// |
2 | | // Name: wx/log.h |
3 | | // Purpose: Assorted wxLogXXX functions, and wxLog (sink for logs) |
4 | | // Author: Vadim Zeitlin |
5 | | // Created: 29/01/98 |
6 | | // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> |
7 | | // Licence: wxWindows licence |
8 | | ///////////////////////////////////////////////////////////////////////////// |
9 | | |
10 | | #ifndef _WX_LOG_H_ |
11 | | #define _WX_LOG_H_ |
12 | | |
13 | | #include "wx/defs.h" |
14 | | #include "wx/cpp.h" |
15 | | |
16 | | // ---------------------------------------------------------------------------- |
17 | | // types |
18 | | // ---------------------------------------------------------------------------- |
19 | | |
20 | | // NB: this is needed even if wxUSE_LOG == 0 |
21 | | typedef unsigned long wxLogLevel; |
22 | | |
23 | | // ---------------------------------------------------------------------------- |
24 | | // headers |
25 | | // ---------------------------------------------------------------------------- |
26 | | |
27 | | #include "wx/string.h" |
28 | | |
29 | | // This is a hack, but this header used to include wx/hashmap.h which, in turn, |
30 | | // included wx/wxcrt.h and it turns out quite some existing code relied on it |
31 | | // by using the CRT wrapper functions declared there without explicitly |
32 | | // including that header, so keep including it from here to let it continue to |
33 | | // compile. |
34 | | #include "wx/wxcrt.h" |
35 | | |
36 | | // ---------------------------------------------------------------------------- |
37 | | // forward declarations |
38 | | // ---------------------------------------------------------------------------- |
39 | | |
40 | | class WXDLLIMPEXP_FWD_BASE wxObject; |
41 | | |
42 | | #if wxUSE_GUI |
43 | | class WXDLLIMPEXP_FWD_CORE wxFrame; |
44 | | #endif // wxUSE_GUI |
45 | | |
46 | | #if wxUSE_LOG |
47 | | |
48 | | #include "wx/arrstr.h" |
49 | | |
50 | | #include <time.h> // for time_t |
51 | | |
52 | | #include "wx/dynarray.h" |
53 | | #include "wx/msgout.h" |
54 | | #include "wx/time.h" |
55 | | |
56 | | #if wxUSE_THREADS |
57 | | #include "wx/thread.h" |
58 | | #endif // wxUSE_THREADS |
59 | | |
60 | | #include <unordered_map> |
61 | | |
62 | | // wxUSE_LOG_DEBUG enables the debug log messages |
63 | | #ifndef wxUSE_LOG_DEBUG |
64 | | #if wxDEBUG_LEVEL |
65 | | #define wxUSE_LOG_DEBUG 1 |
66 | | #else // !wxDEBUG_LEVEL |
67 | | #define wxUSE_LOG_DEBUG 0 |
68 | | #endif |
69 | | #endif |
70 | | |
71 | | // wxUSE_LOG_TRACE enables the trace messages, they are disabled by default |
72 | | #ifndef wxUSE_LOG_TRACE |
73 | | #if wxDEBUG_LEVEL |
74 | | #define wxUSE_LOG_TRACE 1 |
75 | | #else // !wxDEBUG_LEVEL |
76 | | #define wxUSE_LOG_TRACE 0 |
77 | | #endif |
78 | | #endif // wxUSE_LOG_TRACE |
79 | | |
80 | | // wxLOG_COMPONENT identifies the component which generated the log record and |
81 | | // can be #define'd to a user-defined value (ASCII only) when compiling the |
82 | | // user code to use component-based filtering (see wxLog::SetComponentLevel()) |
83 | | #ifndef wxLOG_COMPONENT |
84 | | // this is a variable and not a macro in order to allow the user code to |
85 | | // just #define wxLOG_COMPONENT without #undef'ining it first |
86 | | extern WXDLLIMPEXP_DATA_BASE(const char *) wxLOG_COMPONENT; |
87 | | |
88 | | #ifdef WXBUILDING |
89 | 4 | #define wxLOG_COMPONENT "wx" |
90 | | #endif |
91 | | #endif |
92 | | |
93 | | // ---------------------------------------------------------------------------- |
94 | | // constants |
95 | | // ---------------------------------------------------------------------------- |
96 | | |
97 | | // different standard log levels (you may also define your own) |
98 | | enum wxLogLevelValues |
99 | | { |
100 | | wxLOG_FatalError, // program can't continue, abort immediately |
101 | | wxLOG_Error, // a serious error, user must be informed about it |
102 | | wxLOG_Warning, // user is normally informed about it but may be ignored |
103 | | wxLOG_Message, // normal message (i.e. normal output of a non GUI app) |
104 | | wxLOG_Status, // informational: might go to the status line of GUI app |
105 | | wxLOG_Info, // informational message (a.k.a. 'Verbose') |
106 | | wxLOG_Debug, // never shown to the user, disabled in release mode |
107 | | wxLOG_Trace, // trace messages are also only enabled in debug mode |
108 | | wxLOG_Progress, // used for progress indicator (not yet) |
109 | | wxLOG_User = 100, // user defined levels start here |
110 | | wxLOG_Max = 10000 |
111 | | }; |
112 | | |
113 | | // symbolic trace masks - wxLogTrace("foo", "some trace message...") will be |
114 | | // discarded unless the string "foo" has been added to the list of allowed |
115 | | // ones with AddTraceMask() |
116 | | |
117 | | #define wxTRACE_MemAlloc wxT("memalloc") // trace memory allocation (new/delete) |
118 | | #define wxTRACE_Messages wxT("messages") // trace window messages/X callbacks |
119 | | #define wxTRACE_ResAlloc wxT("resalloc") // trace GDI resource allocation |
120 | | #define wxTRACE_RefCount wxT("refcount") // trace various ref counting operations |
121 | | |
122 | | #ifdef __WINDOWS__ |
123 | | #define wxTRACE_OleCalls wxT("ole") // OLE interface calls |
124 | | #endif |
125 | | |
126 | | #include "wx/iosfwrap.h" |
127 | | |
128 | | // ---------------------------------------------------------------------------- |
129 | | // information about a log record, i.e. unit of log output |
130 | | // ---------------------------------------------------------------------------- |
131 | | |
132 | | class wxLogRecordInfo |
133 | | { |
134 | | public: |
135 | | // default ctor creates an uninitialized object |
136 | | wxLogRecordInfo() |
137 | 2 | { |
138 | 2 | memset(static_cast<void*>(this), 0, sizeof(*this)); |
139 | 2 | } |
140 | | |
141 | | // normal ctor, used by wxLogger specifies the location of the log |
142 | | // statement; its time stamp and thread id are set up here |
143 | | wxLogRecordInfo(const char *filename_, |
144 | | int line_, |
145 | | const char *func_, |
146 | | const char *component_) |
147 | 4 | { |
148 | 4 | filename = filename_; |
149 | 4 | func = func_; |
150 | 4 | line = line_; |
151 | 4 | component = component_; |
152 | | |
153 | | // don't initialize the timestamp yet, we might not need it at all if |
154 | | // the message doesn't end up being logged and otherwise we'll fill it |
155 | | // just before logging it, which won't change it by much |
156 | 4 | timestampMS = 0; |
157 | | #if WXWIN_COMPATIBILITY_3_0 |
158 | | timestamp = 0; |
159 | | #endif // WXWIN_COMPATIBILITY_3_0 |
160 | | |
161 | 4 | #if wxUSE_THREADS |
162 | 4 | threadId = wxThread::GetCurrentId(); |
163 | 4 | #endif // wxUSE_THREADS |
164 | | |
165 | 4 | m_data = nullptr; |
166 | 4 | } |
167 | | |
168 | | // we need to define copy ctor and assignment operator because of m_data |
169 | | wxLogRecordInfo(const wxLogRecordInfo& other) |
170 | 0 | { |
171 | 0 | Copy(other); |
172 | 0 | } |
173 | | |
174 | | wxLogRecordInfo& operator=(const wxLogRecordInfo& other) |
175 | 0 | { |
176 | 0 | if ( &other != this ) |
177 | 0 | { |
178 | 0 | delete m_data; |
179 | 0 | Copy(other); |
180 | 0 | } |
181 | |
|
182 | 0 | return *this; |
183 | 0 | } |
184 | | |
185 | | // dtor is non-virtual, this class is not meant to be derived from |
186 | | ~wxLogRecordInfo() |
187 | 4 | { |
188 | 4 | delete m_data; |
189 | 4 | } |
190 | | |
191 | | |
192 | | // the file name and line number of the file where the log record was |
193 | | // generated, if available or nullptr and 0 otherwise |
194 | | const char *filename; |
195 | | int line; |
196 | | |
197 | | // the name of the function where the log record was generated |
198 | | const char *func; |
199 | | |
200 | | // the name of the component which generated this message, may be null if |
201 | | // not set (i.e. wxLOG_COMPONENT not defined). It must be in ASCII. |
202 | | const char *component; |
203 | | |
204 | | // time of record generation in milliseconds since Epoch |
205 | | wxLongLong_t timestampMS; |
206 | | |
207 | | #if WXWIN_COMPATIBILITY_3_0 |
208 | | // preserved for compatibility only, use timestampMS instead now |
209 | | time_t timestamp; |
210 | | #endif // WXWIN_COMPATIBILITY_3_0 |
211 | | |
212 | | #if wxUSE_THREADS |
213 | | // id of the thread which logged this record |
214 | | wxThreadIdType threadId; |
215 | | #endif // wxUSE_THREADS |
216 | | |
217 | | |
218 | | // store an arbitrary value in this record context |
219 | | // |
220 | | // wxWidgets always uses keys starting with "wx.", e.g. "wx.sys_error" |
221 | | void StoreValue(const wxString& key, wxUIntPtr val) |
222 | 0 | { |
223 | 0 | if ( !m_data ) |
224 | 0 | m_data = new ExtraData; |
225 | |
|
226 | 0 | m_data->numValues[key] = val; |
227 | 0 | } |
228 | | |
229 | | void StoreValue(const wxString& key, const wxString& val) |
230 | 0 | { |
231 | 0 | if ( !m_data ) |
232 | 0 | m_data = new ExtraData; |
233 | |
|
234 | 0 | m_data->strValues[key] = val; |
235 | 0 | } |
236 | | |
237 | | |
238 | | // these functions retrieve the value of either numeric or string key, |
239 | | // return false if not found |
240 | | bool GetNumValue(const wxString& key, wxUIntPtr *val) const |
241 | 0 | { |
242 | 0 | if ( !m_data ) |
243 | 0 | return false; |
244 | | |
245 | 0 | const auto it = m_data->numValues.find(key); |
246 | 0 | if ( it == m_data->numValues.end() ) |
247 | 0 | return false; |
248 | | |
249 | 0 | *val = it->second; |
250 | |
|
251 | 0 | return true; |
252 | 0 | } |
253 | | |
254 | | bool GetStrValue(const wxString& key, wxString *val) const |
255 | 0 | { |
256 | 0 | if ( !m_data ) |
257 | 0 | return false; |
258 | | |
259 | 0 | const auto it = m_data->strValues.find(key); |
260 | 0 | if ( it == m_data->strValues.end() ) |
261 | 0 | return false; |
262 | | |
263 | 0 | *val = it->second; |
264 | |
|
265 | 0 | return true; |
266 | 0 | } |
267 | | |
268 | | private: |
269 | | void Copy(const wxLogRecordInfo& other) |
270 | 0 | { |
271 | 0 | memcpy(static_cast<void*>(this), &other, sizeof(*this)); |
272 | 0 | if ( other.m_data ) |
273 | 0 | m_data = new ExtraData(*other.m_data); |
274 | 0 | } |
275 | | |
276 | | // extra data associated with the log record: this is completely optional |
277 | | // and can be used to pass information from the log function to the log |
278 | | // sink (e.g. wxLogSysError() uses this to pass the error code) |
279 | | struct ExtraData |
280 | | { |
281 | | std::unordered_map<wxString, wxUIntPtr> numValues; |
282 | | std::unordered_map<wxString, wxString> strValues; |
283 | | }; |
284 | | |
285 | | // nullptr if not used |
286 | | ExtraData *m_data; |
287 | | }; |
288 | | |
289 | 0 | #define wxLOG_KEY_TRACE_MASK wxASCII_STR("wx.trace_mask") |
290 | | |
291 | | // ---------------------------------------------------------------------------- |
292 | | // log record: a unit of log output |
293 | | // ---------------------------------------------------------------------------- |
294 | | |
295 | | struct wxLogRecord |
296 | | { |
297 | | wxLogRecord(wxLogLevel level_, |
298 | | const wxString& msg_, |
299 | | const wxLogRecordInfo& info_) |
300 | 0 | : level(level_), |
301 | 0 | msg(msg_), |
302 | 0 | info(info_) |
303 | 0 | { |
304 | 0 | } |
305 | | |
306 | | wxLogLevel level; |
307 | | wxString msg; |
308 | | wxLogRecordInfo info; |
309 | | }; |
310 | | |
311 | | // ---------------------------------------------------------------------------- |
312 | | // Derive from this class to customize format of log messages. |
313 | | // ---------------------------------------------------------------------------- |
314 | | |
315 | | class WXDLLIMPEXP_BASE wxLogFormatter |
316 | | { |
317 | | public: |
318 | | // Default constructor. |
319 | 0 | wxLogFormatter() = default; |
320 | | |
321 | | // Trivial but virtual destructor for the base class. |
322 | 0 | virtual ~wxLogFormatter() = default; |
323 | | |
324 | | |
325 | | // Override this method to implement custom formatting of the given log |
326 | | // record. The default implementation simply prepends a level-dependent |
327 | | // prefix to the message and optionally adds a time stamp. |
328 | | virtual wxString Format(wxLogLevel level, |
329 | | const wxString& msg, |
330 | | const wxLogRecordInfo& info) const; |
331 | | |
332 | | protected: |
333 | | // Override this method to change just the time stamp formatting. It is |
334 | | // called by default Format() implementation. |
335 | | virtual wxString FormatTimeMS(wxLongLong_t msec) const; |
336 | | |
337 | | #if WXWIN_COMPATIBILITY_3_0 |
338 | | // Old function which only worked at second resolution. |
339 | | virtual wxString FormatTime(time_t t) const; |
340 | | #endif // WXWIN_COMPATIBILITY_3_0 |
341 | | }; |
342 | | |
343 | | // Special kind of trivial formatter which simply uses the message unchanged. |
344 | | class wxLogFormatterNone : public wxLogFormatter |
345 | | { |
346 | | public: |
347 | 0 | wxLogFormatterNone() = default; |
348 | | |
349 | | virtual wxString Format(wxLogLevel WXUNUSED(level), |
350 | | const wxString& msg, |
351 | | const wxLogRecordInfo& WXUNUSED(info)) const override |
352 | 0 | { |
353 | 0 | return msg; |
354 | 0 | } |
355 | | }; |
356 | | |
357 | | // ---------------------------------------------------------------------------- |
358 | | // derive from this class to redirect (or suppress, or ...) log messages |
359 | | // normally, only a single instance of this class exists but it's not enforced |
360 | | // ---------------------------------------------------------------------------- |
361 | | |
362 | | class WXDLLIMPEXP_BASE wxLog |
363 | | { |
364 | | public: |
365 | | // ctor |
366 | 0 | wxLog() : m_formatter(new wxLogFormatter) { } |
367 | | |
368 | | // make dtor virtual for all derived classes |
369 | | virtual ~wxLog(); |
370 | | |
371 | | |
372 | | // log messages selection |
373 | | // ---------------------- |
374 | | |
375 | | // these functions allow to completely disable all log messages or disable |
376 | | // log messages at level less important than specified for the current |
377 | | // thread |
378 | | |
379 | | // is logging enabled at all now? |
380 | | static bool IsEnabled() |
381 | 7.99k | { |
382 | 7.99k | #if wxUSE_THREADS |
383 | 7.99k | if ( !wxThread::IsMain() ) |
384 | 0 | return IsThreadLoggingEnabled(); |
385 | 7.99k | #endif // wxUSE_THREADS |
386 | | |
387 | 7.99k | return ms_doLog; |
388 | 7.99k | } |
389 | | |
390 | | // change the flag state, return the previous one |
391 | | static bool EnableLogging(bool enable = true) |
392 | 72.6k | { |
393 | 72.6k | #if wxUSE_THREADS |
394 | 72.6k | if ( !wxThread::IsMain() ) |
395 | 0 | return EnableThreadLogging(enable); |
396 | 72.6k | #endif // wxUSE_THREADS |
397 | | |
398 | 72.6k | const bool doLogOld = ms_doLog; |
399 | 72.6k | ms_doLog = enable; |
400 | 72.6k | return doLogOld; |
401 | 72.6k | } |
402 | | |
403 | | // return the current global log level |
404 | 4 | static wxLogLevel GetLogLevel() { return ms_logLevel; } |
405 | | |
406 | | // set global log level: messages with level > logLevel will not be logged |
407 | 0 | static void SetLogLevel(wxLogLevel logLevel) { ms_logLevel = logLevel; } |
408 | | |
409 | | // set the log level for the given component |
410 | | static void SetComponentLevel(const wxString& component, wxLogLevel level); |
411 | | |
412 | | // return the effective log level for this component, falling back to |
413 | | // parent component and to the default global log level if necessary |
414 | | static wxLogLevel GetComponentLevel(const wxString& component); |
415 | | |
416 | | |
417 | | // is logging of messages from this component enabled at this level? |
418 | | // |
419 | | // usually always called with wxLOG_COMPONENT as second argument |
420 | | static bool IsLevelEnabled(wxLogLevel level, const wxString& component) |
421 | 7.99k | { |
422 | 7.99k | return IsEnabled() && level <= GetComponentLevel(component); |
423 | 7.99k | } |
424 | | |
425 | | |
426 | | // enable/disable messages at wxLOG_Verbose level (only relevant if the |
427 | | // current log level is greater or equal to it) |
428 | | // |
429 | | // notice that verbose mode can be activated by the standard command-line |
430 | | // '--verbose' option |
431 | 0 | static void SetVerbose(bool bVerbose = true) { ms_bVerbose = bVerbose; } |
432 | | |
433 | | // check if verbose messages are enabled |
434 | 0 | static bool GetVerbose() { return ms_bVerbose; } |
435 | | |
436 | | |
437 | | // message buffering |
438 | | // ----------------- |
439 | | |
440 | | // flush shows all messages if they're not logged immediately (FILE |
441 | | // and iostream logs don't need it, but wxLogGui does to avoid showing |
442 | | // 17 modal dialogs one after another) |
443 | | virtual void Flush(); |
444 | | |
445 | | // flush the active target if any and also output any pending messages from |
446 | | // background threads |
447 | | static void FlushActive(); |
448 | | |
449 | | // only one sink is active at each moment get current log target, will call |
450 | | // wxAppTraits::CreateLogTarget() to create one if none exists |
451 | | static wxLog *GetActiveTarget(); |
452 | | |
453 | | // change log target, logger may be null |
454 | | static wxLog *SetActiveTarget(wxLog *logger); |
455 | | |
456 | | #if wxUSE_THREADS |
457 | | // change log target for the current thread only, shouldn't be called from |
458 | | // the main thread as it doesn't use thread-specific log target |
459 | | static wxLog *SetThreadActiveTarget(wxLog *logger); |
460 | | #endif // wxUSE_THREADS |
461 | | |
462 | | // suspend the message flushing of the main target until the next call |
463 | | // to Resume() - this is mainly for internal use (to prevent wxYield() |
464 | | // from flashing the messages) |
465 | 0 | static void Suspend() { ms_suspendCount++; } |
466 | | |
467 | | // must be called for each Suspend()! |
468 | 0 | static void Resume() { ms_suspendCount--; } |
469 | | |
470 | | // should GetActiveTarget() try to create a new log object if the |
471 | | // current is null? |
472 | | static void DontCreateOnDemand(); |
473 | | |
474 | | // Make GetActiveTarget() create a new log object again. |
475 | | static void DoCreateOnDemand(); |
476 | | |
477 | | // log the count of repeating messages instead of logging the messages |
478 | | // multiple times |
479 | | static void SetRepetitionCounting(bool bRepetCounting = true) |
480 | 0 | { ms_bRepetCounting = bRepetCounting; } |
481 | | |
482 | | // gets duplicate counting status |
483 | 0 | static bool GetRepetitionCounting() { return ms_bRepetCounting; } |
484 | | |
485 | | // add string trace mask |
486 | | static void AddTraceMask(const wxString& str); |
487 | | |
488 | | // add string trace mask |
489 | | static void RemoveTraceMask(const wxString& str); |
490 | | |
491 | | // remove all string trace masks |
492 | | static void ClearTraceMasks(); |
493 | | |
494 | | // get string trace masks: note that this is MT-unsafe if other threads can |
495 | | // call AddTraceMask() concurrently |
496 | | static const wxArrayString& GetTraceMasks(); |
497 | | |
498 | | // is this trace mask in the list? |
499 | | static bool IsAllowedTraceMask(const wxString& mask); |
500 | | |
501 | | |
502 | | // log formatting |
503 | | // ----------------- |
504 | | |
505 | | // Change wxLogFormatter object used by wxLog to format the log messages. |
506 | | // |
507 | | // wxLog takes ownership of the pointer passed in but the caller is |
508 | | // responsible for deleting the returned pointer. |
509 | | wxLogFormatter* SetFormatter(wxLogFormatter* formatter); |
510 | | |
511 | | |
512 | | // All the time stamp related functions below only work when the default |
513 | | // wxLogFormatter is being used. Defining a custom formatter overrides them |
514 | | // as it could use its own time stamp format or format messages without |
515 | | // using time stamp at all. |
516 | | |
517 | | |
518 | | // sets the time stamp string format: this is used as strftime() format |
519 | | // string for the log targets which add time stamps to the messages; set |
520 | | // it to empty string to disable time stamping completely. |
521 | 0 | static void SetTimestamp(const wxString& ts) { ms_timestamp = ts; } |
522 | | |
523 | | // disable time stamping of log messages |
524 | 0 | static void DisableTimestamp() { SetTimestamp(wxEmptyString); } |
525 | | |
526 | | |
527 | | // get the current timestamp format string (maybe empty) |
528 | 0 | static const wxString& GetTimestamp() { return ms_timestamp; } |
529 | | |
530 | | |
531 | | |
532 | | // helpers: all functions in this section are mostly for internal use only, |
533 | | // don't call them from your code even if they are not formally deprecated |
534 | | |
535 | | // put the time stamp into the string if ms_timestamp is not empty (don't |
536 | | // change it otherwise); the first overload uses the current time. |
537 | | static void TimeStamp(wxString *str); |
538 | | static void TimeStamp(wxString *str, time_t t); |
539 | | static void TimeStampMS(wxString *str, wxLongLong_t msec); |
540 | | |
541 | | // these methods should only be called from derived classes DoLogRecord(), |
542 | | // DoLogTextAtLevel() and DoLogText() implementations respectively and |
543 | | // shouldn't be called directly, use logging functions instead |
544 | | void LogRecord(wxLogLevel level, |
545 | | const wxString& msg, |
546 | | const wxLogRecordInfo& info) |
547 | 0 | { |
548 | 0 | DoLogRecord(level, msg, info); |
549 | 0 | } |
550 | | |
551 | | void LogTextAtLevel(wxLogLevel level, const wxString& msg) |
552 | 0 | { |
553 | 0 | DoLogTextAtLevel(level, msg); |
554 | 0 | } |
555 | | |
556 | | void LogText(const wxString& msg) |
557 | 0 | { |
558 | 0 | DoLogText(msg); |
559 | 0 | } |
560 | | |
561 | | // this is a helper used by wxLogXXX() functions, don't call it directly |
562 | | // and see DoLog() for function to overload in the derived classes |
563 | | static void OnLog(wxLogLevel level, |
564 | | const wxString& msg, |
565 | | const wxLogRecordInfo& info); |
566 | | |
567 | | // version called when no information about the location of the log record |
568 | | // generation is available (but the time stamp is), it mainly exists for |
569 | | // backwards compatibility, don't use it in new code |
570 | | static void OnLog(wxLogLevel level, const wxString& msg, time_t t); |
571 | | |
572 | | // a helper calling the above overload with current time |
573 | | static void OnLog(wxLogLevel level, const wxString& msg) |
574 | 0 | { |
575 | 0 | OnLog(level, msg, time(nullptr)); |
576 | 0 | } |
577 | | |
578 | | |
579 | | // this method exists for backwards compatibility only, don't use |
580 | 0 | bool HasPendingMessages() const { return true; } |
581 | | |
582 | | protected: |
583 | | // the logging functions that can be overridden: DoLogRecord() is called |
584 | | // for every "record", i.e. a unit of log output, to be logged and by |
585 | | // default formats the message and passes it to DoLogTextAtLevel() which in |
586 | | // turn passes it to DoLogText() by default |
587 | | |
588 | | // override this method if you want to change message formatting or do |
589 | | // dynamic filtering |
590 | | virtual void DoLogRecord(wxLogLevel level, |
591 | | const wxString& msg, |
592 | | const wxLogRecordInfo& info); |
593 | | |
594 | | // override this method to redirect output to different channels depending |
595 | | // on its level only; if even the level doesn't matter, override |
596 | | // DoLogText() instead |
597 | | virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg); |
598 | | |
599 | | // this function is not pure virtual as it might not be needed if you do |
600 | | // the logging in overridden DoLogRecord() or DoLogTextAtLevel() directly |
601 | | // but if you do not override them in your derived class you must override |
602 | | // this one as the default implementation of it simply asserts |
603 | | virtual void DoLogText(const wxString& msg); |
604 | | |
605 | | // log a message indicating the number of times the previous message was |
606 | | // repeated if previous repetition counter is strictly positive, does |
607 | | // nothing otherwise; return the old value of repetition counter |
608 | | unsigned LogLastRepeatIfNeeded(); |
609 | | |
610 | | private: |
611 | | #if wxUSE_THREADS |
612 | | // called from FlushActive() to really log any buffered messages logged |
613 | | // from the other threads |
614 | | void FlushThreadMessages(); |
615 | | |
616 | | // these functions are called for non-main thread only by IsEnabled() and |
617 | | // EnableLogging() respectively |
618 | | static bool IsThreadLoggingEnabled(); |
619 | | static bool EnableThreadLogging(bool enable = true); |
620 | | #endif // wxUSE_THREADS |
621 | | |
622 | | // get the active log target for the main thread, auto-creating it if |
623 | | // necessary |
624 | | // |
625 | | // this is called from GetActiveTarget() and OnLog() when they're called |
626 | | // from the main thread |
627 | | static wxLog *GetMainThreadActiveTarget(); |
628 | | |
629 | | // called from OnLog() if it's called from the main thread or if we have a |
630 | | // (presumably MT-safe) thread-specific logger and by FlushThreadMessages() |
631 | | // when it plays back the buffered messages logged from the other threads |
632 | | void CallDoLogNow(wxLogLevel level, |
633 | | const wxString& msg, |
634 | | const wxLogRecordInfo& info); |
635 | | |
636 | | |
637 | | // variables |
638 | | // ---------------- |
639 | | |
640 | | wxLogFormatter *m_formatter; // We own this pointer. |
641 | | |
642 | | |
643 | | // static variables |
644 | | // ---------------- |
645 | | |
646 | | // if true, don't log the same message multiple times, only log it once |
647 | | // with the number of times it was repeated |
648 | | static bool ms_bRepetCounting; |
649 | | |
650 | | static wxLog *ms_pLogger; // currently active log sink |
651 | | static bool ms_doLog; // false => all logging disabled |
652 | | static bool ms_bAutoCreate; // create new log targets on demand? |
653 | | static bool ms_bVerbose; // false => ignore LogInfo messages |
654 | | |
655 | | static wxLogLevel ms_logLevel; // limit logging to levels <= ms_logLevel |
656 | | |
657 | | static size_t ms_suspendCount; // if positive, logs are not flushed |
658 | | |
659 | | // format string for strftime(), if empty, time stamping log messages is |
660 | | // disabled |
661 | | static wxString ms_timestamp; |
662 | | |
663 | | wxDECLARE_NO_COPY_CLASS(wxLog); |
664 | | }; |
665 | | |
666 | | // ---------------------------------------------------------------------------- |
667 | | // "trivial" derivations of wxLog |
668 | | // ---------------------------------------------------------------------------- |
669 | | |
670 | | // log everything except for the debug/trace messages (which are passed to |
671 | | // wxMessageOutputDebug) to a buffer |
672 | | class WXDLLIMPEXP_BASE wxLogBuffer : public wxLog |
673 | | { |
674 | | public: |
675 | 0 | wxLogBuffer() = default; |
676 | | |
677 | | // get the string contents with all messages logged |
678 | 0 | const wxString& GetBuffer() const { return m_str; } |
679 | | |
680 | | // clear all the messages, this, in particular, prevents them from being |
681 | | // flushed |
682 | 0 | void Clear() { m_str.clear(); } |
683 | | |
684 | | // show the buffer contents to the user in the best possible way (this uses |
685 | | // wxMessageOutputMessageBox) and clear it |
686 | | virtual void Flush() override; |
687 | | |
688 | | protected: |
689 | | virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg) override; |
690 | | |
691 | | private: |
692 | | wxString m_str; |
693 | | |
694 | | wxDECLARE_NO_COPY_CLASS(wxLogBuffer); |
695 | | }; |
696 | | |
697 | | |
698 | | // log everything to a "FILE *", stderr by default |
699 | | class WXDLLIMPEXP_BASE wxLogStderr : public wxLog, |
700 | | protected wxMessageOutputStderr |
701 | | { |
702 | | public: |
703 | | // redirect log output to a FILE |
704 | | wxLogStderr(FILE *fp = nullptr, |
705 | | const wxMBConv &conv = wxConvWhateverWorks); |
706 | | |
707 | | protected: |
708 | | // implement sink function |
709 | | virtual void DoLogText(const wxString& msg) override; |
710 | | |
711 | | wxDECLARE_NO_COPY_CLASS(wxLogStderr); |
712 | | }; |
713 | | |
714 | | #if wxUSE_STD_IOSTREAM |
715 | | |
716 | | // log everything to an "ostream", cerr by default |
717 | | class WXDLLIMPEXP_BASE wxLogStream : public wxLog, |
718 | | private wxMessageOutputWithConv |
719 | | { |
720 | | public: |
721 | | // redirect log output to an ostream |
722 | | wxLogStream(std::ostream *ostr = (std::ostream *) nullptr, |
723 | | const wxMBConv& conv = wxConvWhateverWorks); |
724 | | |
725 | | protected: |
726 | | // implement sink function |
727 | | virtual void DoLogText(const wxString& msg) override; |
728 | | |
729 | | // using ptr here to avoid including <iostream.h> from this file |
730 | | std::ostream *m_ostr; |
731 | | |
732 | | wxDECLARE_NO_COPY_CLASS(wxLogStream); |
733 | | }; |
734 | | |
735 | | #endif // wxUSE_STD_IOSTREAM |
736 | | |
737 | | // ---------------------------------------------------------------------------- |
738 | | // /dev/null log target: suppress logging until this object goes out of scope |
739 | | // ---------------------------------------------------------------------------- |
740 | | |
741 | | // example of usage: |
742 | | /* |
743 | | void Foo() |
744 | | { |
745 | | wxFile file; |
746 | | |
747 | | // wxFile.Open() normally complains if file can't be opened, we don't |
748 | | // want it |
749 | | wxLogNull logNo; |
750 | | |
751 | | if ( !file.Open("bar") ) |
752 | | ... process error ourselves ... |
753 | | |
754 | | // ~wxLogNull called, old log sink restored |
755 | | } |
756 | | */ |
757 | | class WXDLLIMPEXP_BASE wxLogNull |
758 | | { |
759 | | public: |
760 | 36.3k | wxLogNull() : m_flagOld(wxLog::EnableLogging(false)) { } |
761 | 36.3k | ~wxLogNull() { (void)wxLog::EnableLogging(m_flagOld); } |
762 | | |
763 | | private: |
764 | | bool m_flagOld; // the previous value of the wxLog::ms_doLog |
765 | | }; |
766 | | |
767 | | // ---------------------------------------------------------------------------- |
768 | | // Collect all logged messages into a (multiline) string. |
769 | | // ---------------------------------------------------------------------------- |
770 | | |
771 | | // This class is supposed to be used as a local variable and collects, without |
772 | | // showing them, all the messages logged during its lifetime. |
773 | | class wxLogCollector |
774 | | { |
775 | | public: |
776 | | wxLogCollector() |
777 | 0 | : m_logOrig{wxLog::SetActiveTarget(&m_logBuf)} |
778 | 0 | { |
779 | 0 | delete m_logBuf.SetFormatter(new wxLogFormatterNone{}); |
780 | 0 | } |
781 | | |
782 | | ~wxLogCollector() |
783 | 0 | { |
784 | | // Don't flush the messages in the buffer. |
785 | 0 | m_logBuf.Clear(); |
786 | |
|
787 | 0 | wxLog::SetActiveTarget(m_logOrig); |
788 | 0 | } |
789 | | |
790 | | const wxString& GetMessages() const |
791 | 0 | { |
792 | 0 | return m_logBuf.GetBuffer(); |
793 | 0 | } |
794 | | |
795 | | private: |
796 | | wxLogBuffer m_logBuf; |
797 | | wxLog* const m_logOrig; |
798 | | |
799 | | wxDECLARE_NO_COPY_CLASS(wxLogCollector); |
800 | | }; |
801 | | |
802 | | // ---------------------------------------------------------------------------- |
803 | | // chaining log target: installs itself as a log target and passes all |
804 | | // messages to the real log target given to it in the ctor but also forwards |
805 | | // them to the previously active one |
806 | | // |
807 | | // note that you don't have to call SetActiveTarget() with this class, it |
808 | | // does it itself in its ctor |
809 | | // ---------------------------------------------------------------------------- |
810 | | |
811 | | class WXDLLIMPEXP_BASE wxLogChain : public wxLog |
812 | | { |
813 | | public: |
814 | | wxLogChain(wxLog *logger); |
815 | | virtual ~wxLogChain(); |
816 | | |
817 | | // change the new log target |
818 | | void SetLog(wxLog *logger); |
819 | | |
820 | | // this can be used to temporarily disable (and then re-enable) passing |
821 | | // messages to the old logger (by default we do pass them) |
822 | 0 | void PassMessages(bool bDoPass) { m_bPassMessages = bDoPass; } |
823 | | |
824 | | // are we passing the messages to the previous log target? |
825 | 0 | bool IsPassingMessages() const { return m_bPassMessages; } |
826 | | |
827 | | // return the previous log target (may be null) |
828 | 0 | wxLog *GetOldLog() const { return m_logOld; } |
829 | | |
830 | | // override base class version to flush the old logger as well |
831 | | virtual void Flush() override; |
832 | | |
833 | | // call to avoid destroying the old log target |
834 | 0 | void DetachOldLog() { m_logOld = nullptr; } |
835 | | |
836 | | protected: |
837 | | // pass the record to the old logger if needed |
838 | | virtual void DoLogRecord(wxLogLevel level, |
839 | | const wxString& msg, |
840 | | const wxLogRecordInfo& info) override; |
841 | | |
842 | | private: |
843 | | // the current log target |
844 | | wxLog *m_logNew; |
845 | | |
846 | | // the previous log target |
847 | | wxLog *m_logOld; |
848 | | |
849 | | // do we pass the messages to the old logger? |
850 | | bool m_bPassMessages; |
851 | | |
852 | | wxDECLARE_NO_COPY_CLASS(wxLogChain); |
853 | | }; |
854 | | |
855 | | // a chain log target which uses itself as the new logger |
856 | | |
857 | | #define wxLogPassThrough wxLogInterposer |
858 | | |
859 | | class WXDLLIMPEXP_BASE wxLogInterposer : public wxLogChain |
860 | | { |
861 | | public: |
862 | | wxLogInterposer(); |
863 | | |
864 | | private: |
865 | | wxDECLARE_NO_COPY_CLASS(wxLogInterposer); |
866 | | }; |
867 | | |
868 | | // a temporary interposer which doesn't destroy the old log target |
869 | | // (calls DetachOldLog) |
870 | | |
871 | | class WXDLLIMPEXP_BASE wxLogInterposerTemp : public wxLogChain |
872 | | { |
873 | | public: |
874 | | wxLogInterposerTemp(); |
875 | | |
876 | | private: |
877 | | wxDECLARE_NO_COPY_CLASS(wxLogInterposerTemp); |
878 | | }; |
879 | | |
880 | | #if wxUSE_GUI |
881 | | // include GUI log targets: |
882 | | #include "wx/generic/logg.h" |
883 | | #endif // wxUSE_GUI |
884 | | |
885 | | // ---------------------------------------------------------------------------- |
886 | | // wxLogger |
887 | | // ---------------------------------------------------------------------------- |
888 | | |
889 | | // wxLogger is a helper class used by wxLogXXX() functions implementation, |
890 | | // don't use it directly as it's experimental and subject to change (OTOH it |
891 | | // might become public in the future if it's deemed to be useful enough) |
892 | | |
893 | | // contains information about the context from which a log message originates |
894 | | // and provides Log() vararg method which forwards to wxLog::OnLog() and passes |
895 | | // this context to it |
896 | | class wxLogger |
897 | | { |
898 | | public: |
899 | | // ctor takes the basic information about the log record |
900 | | wxLogger(wxLogLevel level, |
901 | | const char *filename, |
902 | | int line, |
903 | | const char *func, |
904 | | const char *component) |
905 | 4 | : m_level(level), |
906 | 4 | m_info(filename, line, func, component) |
907 | 4 | { |
908 | 4 | } |
909 | | |
910 | | // store extra data in our log record and return this object itself (so |
911 | | // that further calls to its functions could be chained) |
912 | | template <typename T> |
913 | | wxLogger& Store(const wxString& key, T val) |
914 | 0 | { |
915 | 0 | m_info.StoreValue(key, val); |
916 | 0 | return *this; |
917 | 0 | } Unexecuted instantiation: wxLogger& wxLogger::Store<long>(wxString const&, long) Unexecuted instantiation: wxLogger& wxLogger::Store<unsigned long>(wxString const&, unsigned long) Unexecuted instantiation: wxLogger& wxLogger::Store<wxString>(wxString const&, wxString) |
918 | | |
919 | | // hack for "overloaded" wxLogXXX() functions: calling this method |
920 | | // indicates that we may have an extra first argument preceding the format |
921 | | // string and that if we do have it, we should store it in m_info using the |
922 | | // given key (while by default 0 value will be used) |
923 | | wxLogger& MaybeStore(const char* key, wxUIntPtr value = 0) |
924 | 0 | { |
925 | 0 | wxASSERT_MSG( m_optKey.empty(), "can only have one optional value" ); |
926 | | |
927 | | // We only use keys defined in this file and we can be sure they |
928 | | // contain ASCII characters only. |
929 | 0 | m_optKey = wxString::FromAscii(key); |
930 | |
|
931 | 0 | m_info.StoreValue(m_optKey, value); |
932 | 0 | return *this; |
933 | 0 | } |
934 | | |
935 | | |
936 | | // non-vararg function used by wxVLogXXX(): |
937 | | |
938 | | // log the message at the level specified in the ctor if this log message |
939 | | // is enabled |
940 | | void LogV(const wxString& format, va_list argptr) |
941 | 0 | { |
942 | 0 | // remember that fatal errors can't be disabled |
943 | 0 | if ( m_level == wxLOG_FatalError || |
944 | 0 | wxLog::IsLevelEnabled(m_level, wxASCII_STR(m_info.component)) ) |
945 | 0 | DoCallOnLog(wxString::FormatV(format, argptr)); |
946 | 0 | } |
947 | | |
948 | | // overloads used by functions with optional leading arguments (whose |
949 | | // values are stored in the key passed to MaybeStore()) |
950 | | void LogV(long num, const wxString& format, va_list argptr) |
951 | 0 | { |
952 | 0 | Store(m_optKey, num); |
953 | 0 |
|
954 | 0 | LogV(format, argptr); |
955 | 0 | } |
956 | | |
957 | | void LogV(void *ptr, const wxString& format, va_list argptr) |
958 | 0 | { |
959 | 0 | Store(m_optKey, wxPtrToUInt(ptr)); |
960 | 0 |
|
961 | 0 | LogV(format, argptr); |
962 | 0 | } |
963 | | |
964 | | void LogVTrace(const wxString& mask, const wxString& format, va_list argptr) |
965 | 0 | { |
966 | 0 | if ( !wxLog::IsAllowedTraceMask(mask) ) |
967 | 0 | return; |
968 | 0 |
|
969 | 0 | Store(wxLOG_KEY_TRACE_MASK, mask); |
970 | 0 |
|
971 | 0 | LogV(format, argptr); |
972 | 0 | } |
973 | | |
974 | | |
975 | | // variadic functions used by wxLogXXX(): |
976 | | |
977 | | // we need to use an extra class with a more restricted set of ctors than |
978 | | // wxString itself, as otherwise we'd get ambiguities between constructing |
979 | | // wxString from long |
980 | | struct FormatString : wxString |
981 | | { |
982 | 0 | FormatString(const wxString& str) : wxString(str) {} |
983 | 0 | FormatString(const wxCStrData& str) : wxString(str) {} |
984 | 0 | FormatString(const wchar_t *str) : wxString(str) {} |
985 | 0 | FormatString(const wxScopedWCharBuffer& str) : wxString(str) {} |
986 | | #ifndef wxNO_IMPLICIT_WXSTRING_ENCODING |
987 | 0 | FormatString(const char *str) : wxString(str) {} |
988 | 0 | FormatString(const wxScopedCharBuffer& str) : wxString(str) {} |
989 | | #endif // !wxNO_IMPLICIT_WXSTRING_ENCODING |
990 | | }; |
991 | | |
992 | | // will log the message at the level specified in the ctor |
993 | | // |
994 | | // notice that this function supposes that the caller already checked that |
995 | | // the level was enabled and does no checks itself |
996 | | template <typename... Targs> |
997 | | void Log(const FormatString& format, Targs... args) |
998 | 0 | { |
999 | 0 | DoCallOnLog(wxString::Format(format, args...)); |
1000 | 0 | } Unexecuted instantiation: void wxLogger::Log<wxString, wxString, wxString>(wxLogger::FormatString const&, wxString, wxString, wxString) Unexecuted instantiation: void wxLogger::Log<long, wxString>(wxLogger::FormatString const&, long, wxString) Unexecuted instantiation: void wxLogger::Log<char, unsigned int, wxCStrData>(wxLogger::FormatString const&, char, unsigned int, wxCStrData) Unexecuted instantiation: void wxLogger::Log<wxString>(wxLogger::FormatString const&, wxString) Unexecuted instantiation: void wxLogger::Log<wxString, wchar_t, unsigned long>(wxLogger::FormatString const&, wxString, wchar_t, unsigned long) Unexecuted instantiation: void wxLogger::Log<wxString, unsigned long, wchar_t const*>(wxLogger::FormatString const&, wxString, unsigned long, wchar_t const*) Unexecuted instantiation: void wxLogger::Log<wxString, unsigned long>(wxLogger::FormatString const&, wxString, unsigned long) Unexecuted instantiation: void wxLogger::Log<wxString, unsigned long, wxString>(wxLogger::FormatString const&, wxString, unsigned long, wxString) Unexecuted instantiation: void wxLogger::Log<wxString, unsigned long, wxString, int>(wxLogger::FormatString const&, wxString, unsigned long, wxString, int) Unexecuted instantiation: void wxLogger::Log<wchar_t>(wxLogger::FormatString const&, wchar_t) Unexecuted instantiation: void wxLogger::Log<wxString, wxString>(wxLogger::FormatString const&, wxString, wxString) Unexecuted instantiation: void wxLogger::Log<wxCStrData>(wxLogger::FormatString const&, wxCStrData) Unexecuted instantiation: void wxLogger::Log<wxCStrData, wxCStrData>(wxLogger::FormatString const&, wxCStrData, wxCStrData) Unexecuted instantiation: void wxLogger::Log<long, wxCStrData>(wxLogger::FormatString const&, long, wxCStrData) Unexecuted instantiation: void wxLogger::Log<wchar_t const*>(wxLogger::FormatString const&, wchar_t const*) Unexecuted instantiation: void wxLogger::Log<wchar_t const*, wchar_t const*>(wxLogger::FormatString const&, wchar_t const*, wchar_t const*) Unexecuted instantiation: void wxLogger::Log<wchar_t const*, int, wchar_t const*, long, wxString>(wxLogger::FormatString const&, wchar_t const*, int, wchar_t const*, long, wxString) Unexecuted instantiation: void wxLogger::Log<char*>(wxLogger::FormatString const&, char*) Unexecuted instantiation: void wxLogger::Log<int, wxFDIOManager::Direction>(wxLogger::FormatString const&, int, wxFDIOManager::Direction) Unexecuted instantiation: void wxLogger::Log<unsigned long>(wxLogger::FormatString const&, unsigned long) Unexecuted instantiation: void wxLogger::Log<int>(wxLogger::FormatString const&, int) Unexecuted instantiation: void wxLogger::Log<unsigned int>(wxLogger::FormatString const&, unsigned int) Unexecuted instantiation: void wxLogger::Log<void*>(wxLogger::FormatString const&, void*) Unexecuted instantiation: void wxLogger::Log<wchar_t const*, int, wxString, long, wxString>(wxLogger::FormatString const&, wchar_t const*, int, wxString, long, wxString) Unexecuted instantiation: void wxLogger::Log<int, int>(wxLogger::FormatString const&, int, int) Unexecuted instantiation: void wxLogger::Log<char const*>(wxLogger::FormatString const&, char const*) |
1001 | | |
1002 | | // overload used when there are no format specifiers: we want to avoid |
1003 | | // using wxString::Format() in this case both because this would be |
1004 | | // needlessly inefficient and because it would misinterpret any "%" |
1005 | | // characters in the string as introducing format specifiers |
1006 | | void Log(const wxString& s) |
1007 | 0 | { |
1008 | 0 | DoCallOnLog(s); |
1009 | 0 | } |
1010 | | |
1011 | | // same as Log() but with an extra numeric or pointer parameters: this is |
1012 | | // used to pass an optional value by storing it in m_info under the name |
1013 | | // passed to MaybeStore() and is required to support "overloaded" versions |
1014 | | // of wxLogStatus() and wxLogSysError() |
1015 | | template <typename... Targs> |
1016 | | void Log(long num, const FormatString& format, Targs... args) |
1017 | 0 | { |
1018 | 0 | Store(m_optKey, num); |
1019 | |
|
1020 | 0 | DoCallOnLog(wxString::Format(format, args...)); |
1021 | 0 | } |
1022 | | |
1023 | | void Log(long num, const wxString& s) |
1024 | 0 | { |
1025 | 0 | Store(m_optKey, num); |
1026 | |
|
1027 | 0 | DoCallOnLog(s); |
1028 | 0 | } |
1029 | | |
1030 | | // unfortunately we can't use "void *" here as we get overload ambiguities |
1031 | | // with Log(FormatString, ...) when the first argument is a "char *" or |
1032 | | // "wchar_t *" then -- so we only allow passing wxObject here, which is |
1033 | | // ugly but fine in practice as this overload is only used by wxLogStatus() |
1034 | | // whose first argument is a wxFrame |
1035 | | template <typename... Targs> |
1036 | | void Log(wxObject* ptr, const FormatString& format, Targs... args) |
1037 | | { |
1038 | | Store(m_optKey, wxPtrToUInt(ptr)); |
1039 | | |
1040 | | DoCallOnLog(wxString::Format(format, args...)); |
1041 | | } |
1042 | | |
1043 | | void Log(wxObject* ptr, const wxString& s) |
1044 | 0 | { |
1045 | 0 | Store(m_optKey, wxPtrToUInt(ptr)); |
1046 | 0 |
|
1047 | 0 | DoCallOnLog(s); |
1048 | 0 | } |
1049 | | |
1050 | | // log the message at the level specified as its first argument |
1051 | | // |
1052 | | // as the macros don't have access to the level argument in this case, this |
1053 | | // function does check that the level is enabled itself |
1054 | | template <typename... Targs> |
1055 | | void LogAtLevel(wxLogLevel level, const wxString& format, Targs... args) |
1056 | | { |
1057 | | if ( !wxLog::IsLevelEnabled(level, wxASCII_STR(m_info.component)) ) |
1058 | | return; |
1059 | | |
1060 | | DoCallOnLog(level, wxString::Format(format, args...)); |
1061 | | } |
1062 | | |
1063 | | void LogAtLevel(wxLogLevel level, const wxString& s) |
1064 | 0 | { |
1065 | 0 | if ( !wxLog::IsLevelEnabled(level, wxASCII_STR(m_info.component)) ) |
1066 | 0 | return; |
1067 | 0 |
|
1068 | 0 | DoCallOnLog(level, s); |
1069 | 0 | } |
1070 | | |
1071 | | // special versions for wxLogTrace() which is passed either string or |
1072 | | // integer mask as first argument determining whether the message should be |
1073 | | // logged or not |
1074 | | template <typename... Targs> |
1075 | | void LogTrace(const wxString& mask, const wxString& format, Targs... args) |
1076 | 4 | { |
1077 | 4 | if ( !wxLog::IsAllowedTraceMask(mask) ) |
1078 | 4 | return; |
1079 | | |
1080 | 0 | Store(wxLOG_KEY_TRACE_MASK, mask); |
1081 | |
|
1082 | 0 | DoCallOnLog(wxString::Format(format, args...)); |
1083 | 0 | } Unexecuted instantiation: void wxLogger::LogTrace<wxString, wxString, wxString>(wxString const&, wxString const&, wxString, wxString, wxString) Unexecuted instantiation: void wxLogger::LogTrace<wxString>(wxString const&, wxString const&, wxString) Unexecuted instantiation: void wxLogger::LogTrace<wxString, wxString>(wxString const&, wxString const&, wxString, wxString) Unexecuted instantiation: void wxLogger::LogTrace<void*, void*, void*>(wxString const&, wxString const&, void*, void*, void*) Unexecuted instantiation: void wxLogger::LogTrace<unsigned long>(wxString const&, wxString const&, unsigned long) Unexecuted instantiation: void wxLogger::LogTrace<wchar_t const*>(wxString const&, wxString const&, wchar_t const*) Unexecuted instantiation: void wxLogger::LogTrace<wxCStrData>(wxString const&, wxString const&, wxCStrData) Unexecuted instantiation: void wxLogger::LogTrace<wxString, wchar_t const*>(wxString const&, wxString const&, wxString, wchar_t const*) Unexecuted instantiation: void wxLogger::LogTrace<wxCStrData, char const*>(wxString const&, wxString const&, wxCStrData, char const*) void wxLogger::LogTrace<char const*>(wxString const&, wxString const&, char const*) Line | Count | Source | 1076 | 4 | { | 1077 | 4 | if ( !wxLog::IsAllowedTraceMask(mask) ) | 1078 | 4 | return; | 1079 | | | 1080 | 0 | Store(wxLOG_KEY_TRACE_MASK, mask); | 1081 | |
| 1082 | 0 | DoCallOnLog(wxString::Format(format, args...)); | 1083 | 0 | } |
Unexecuted instantiation: void wxLogger::LogTrace<char const*, wxString>(wxString const&, wxString const&, char const*, wxString) Unexecuted instantiation: void wxLogger::LogTrace<wxString, wxString, wxString, wxString, wxString>(wxString const&, wxString const&, wxString, wxString, wxString, wxString, wxString) Unexecuted instantiation: void wxLogger::LogTrace<int>(wxString const&, wxString const&, int) Unexecuted instantiation: void wxLogger::LogTrace<int, wxString>(wxString const&, wxString const&, int, wxString) Unexecuted instantiation: void wxLogger::LogTrace<void*, wchar_t const*, wchar_t const*>(wxString const&, wxString const&, void*, wchar_t const*, wchar_t const*) Unexecuted instantiation: void wxLogger::LogTrace<unsigned long, wchar_t const*>(wxString const&, wxString const&, unsigned long, wchar_t const*) Unexecuted instantiation: void wxLogger::LogTrace<void*>(wxString const&, wxString const&, void*) Unexecuted instantiation: void wxLogger::LogTrace<void*, unsigned long>(wxString const&, wxString const&, void*, unsigned long) Unexecuted instantiation: void wxLogger::LogTrace<int, int>(wxString const&, wxString const&, int, int) Unexecuted instantiation: void wxLogger::LogTrace<char const*, int>(wxString const&, wxString const&, char const*, int) Unexecuted instantiation: void wxLogger::LogTrace<int, bool, int, bool>(wxString const&, wxString const&, int, bool, int, bool) Unexecuted instantiation: void wxLogger::LogTrace<int, bool, bool, bool>(wxString const&, wxString const&, int, bool, bool, bool) Unexecuted instantiation: void wxLogger::LogTrace<int, wxFDIOHandler*, int>(wxString const&, wxString const&, int, wxFDIOHandler*, int) |
1084 | | |
1085 | | void LogTrace(const wxString& mask, const wxString& s) |
1086 | 0 | { |
1087 | 0 | if ( !wxLog::IsAllowedTraceMask(mask) ) |
1088 | 0 | return; |
1089 | | |
1090 | 0 | Store(wxLOG_KEY_TRACE_MASK, mask); |
1091 | |
|
1092 | 0 | DoCallOnLog(s); |
1093 | 0 | } |
1094 | | |
1095 | | private: |
1096 | | void DoCallOnLog(wxLogLevel level, const wxString& msg) |
1097 | 0 | { |
1098 | | // As explained in wxLogRecordInfo ctor, we don't initialize its |
1099 | | // timestamp to avoid calling time() unnecessary, but now that we are |
1100 | | // about to log the message, we do need to do it. |
1101 | 0 | m_info.timestampMS = wxGetUTCTimeMillis().GetValue(); |
1102 | |
|
1103 | | #if WXWIN_COMPATIBILITY_3_0 |
1104 | | m_info.timestamp = m_info.timestampMS / 1000; |
1105 | | #endif // WXWIN_COMPATIBILITY_3_0 |
1106 | |
|
1107 | 0 | wxLog::OnLog(level, msg, m_info); |
1108 | 0 | } |
1109 | | |
1110 | | void DoCallOnLog(const wxString& msg) |
1111 | 0 | { |
1112 | 0 | DoCallOnLog(m_level, msg); |
1113 | 0 | } |
1114 | | |
1115 | | |
1116 | | const wxLogLevel m_level; |
1117 | | wxLogRecordInfo m_info; |
1118 | | |
1119 | | wxString m_optKey; |
1120 | | |
1121 | | wxDECLARE_NO_COPY_CLASS(wxLogger); |
1122 | | }; |
1123 | | |
1124 | | // ============================================================================ |
1125 | | // global functions |
1126 | | // ============================================================================ |
1127 | | |
1128 | | // ---------------------------------------------------------------------------- |
1129 | | // get error code/error message from system in a portable way |
1130 | | // ---------------------------------------------------------------------------- |
1131 | | |
1132 | | // return the last system error code |
1133 | | WXDLLIMPEXP_BASE unsigned long wxSysErrorCode(); |
1134 | | |
1135 | | // return the error message for given (or last if 0) error code |
1136 | | WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); |
1137 | | |
1138 | | // return the error message for given (or last if 0) error code |
1139 | | WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0); |
1140 | | |
1141 | | // ---------------------------------------------------------------------------- |
1142 | | // define wxLog<level>() functions which can be used by application instead of |
1143 | | // stdio, iostream &c for log messages for easy redirection |
1144 | | // ---------------------------------------------------------------------------- |
1145 | | |
1146 | | /* |
1147 | | The code below is unreadable because it (unfortunately unavoidably) |
1148 | | contains a lot of macro magic but all it does is to define wxLogXXX() such |
1149 | | that you can call them as vararg functions to log a message at the |
1150 | | corresponding level. |
1151 | | |
1152 | | More precisely, it defines: |
1153 | | |
1154 | | - wxLog{FatalError,Error,Warning,Message,Verbose,Debug}() functions |
1155 | | taking the format string and additional vararg arguments if needed. |
1156 | | - wxLogGeneric(wxLogLevel level, const wxString& format, ...) which |
1157 | | takes the log level explicitly. |
1158 | | - wxLogSysError(const wxString& format, ...) and wxLogSysError(long |
1159 | | err, const wxString& format, ...) which log a wxLOG_Error severity |
1160 | | message with the error message corresponding to the system error code |
1161 | | err or the last error. |
1162 | | - wxLogStatus(const wxString& format, ...) which logs the message into |
1163 | | the status bar of the main application window and its overload |
1164 | | wxLogStatus(wxFrame *frame, const wxString& format, ...) which logs it |
1165 | | into the status bar of the specified frame. |
1166 | | - wxLogTrace(Mask mask, const wxString& format, ...) which only logs |
1167 | | the message is the specified mask is enabled. This comes in two kinds: |
1168 | | Mask can be a wxString or a long. Both are deprecated. |
1169 | | |
1170 | | In addition, wxVLogXXX() versions of all the functions above are also |
1171 | | defined. They take a va_list argument instead of "...". |
1172 | | */ |
1173 | | |
1174 | | // creates wxLogger object for the current location |
1175 | | #define wxMAKE_LOGGER(level) \ |
1176 | 4 | wxLogger(wxLOG_##level, __FILE__, __LINE__, __func__, wxLOG_COMPONENT) |
1177 | | |
1178 | | // this macro generates the expression which logs whatever follows it in |
1179 | | // parentheses at the level specified as argument |
1180 | 8.08k | #define wxDO_LOG(level) wxDO_LOG_WITH_FUNC(level, Log) |
1181 | | |
1182 | | // generalization of the macro above that uses the given function of wxLogger |
1183 | | // object rather than the default "Log" |
1184 | 4 | #define wxDO_LOG_WITH_FUNC(level, func) wxMAKE_LOGGER(level).func |
1185 | | |
1186 | | // this is the non-vararg equivalent |
1187 | | #define wxDO_LOGV(level, format, argptr) \ |
1188 | | wxMAKE_LOGGER(level).LogV(format, argptr) |
1189 | | |
1190 | | // Macro evaluating to true if logging at the given level is enabled. |
1191 | | #define wxLOG_IS_ENABLED(level) \ |
1192 | | wxLog::IsLevelEnabled(wxLOG_##level, wxASCII_STR(wxLOG_COMPONENT)) |
1193 | | |
1194 | | // Macro used to define most of the actual wxLogXXX() macros: just calls |
1195 | | // wxLogger::Log(), if logging at the specified level is enabled. |
1196 | | #define wxDO_LOG_IF_ENABLED(level) \ |
1197 | 7.98k | wxDO_IF(wxLOG_IS_ENABLED(level)) \ |
1198 | 825 | wxDO_LOG(level) |
1199 | | |
1200 | | // Similar to above, but calls the given function instead of Log(). |
1201 | | #define wxDO_LOG_IF_ENABLED_WITH_FUNC(level, func) \ |
1202 | 4 | wxDO_IF(wxLOG_IS_ENABLED(level)) \ |
1203 | 4 | wxDO_LOG_WITH_FUNC(level, func) |
1204 | | |
1205 | | // wxLogFatalError() is special as it can't be disabled |
1206 | 0 | #define wxLogFatalError wxDO_LOG(FatalError) |
1207 | | #define wxVLogFatalError(format, argptr) wxDO_LOGV(FatalError, format, argptr) |
1208 | | |
1209 | 4.33k | #define wxLogError wxDO_LOG_IF_ENABLED(Error) |
1210 | | #define wxVLogError(format, argptr) wxDO_LOGV(Error, format, argptr) |
1211 | | |
1212 | 3.02k | #define wxLogWarning wxDO_LOG_IF_ENABLED(Warning) |
1213 | | #define wxVLogWarning(format, argptr) wxDO_LOGV(Warning, format, argptr) |
1214 | | |
1215 | 0 | #define wxLogMessage wxDO_LOG_IF_ENABLED(Message) |
1216 | | #define wxVLogMessage(format, argptr) wxDO_LOGV(Message, format, argptr) |
1217 | | |
1218 | | #define wxLogInfo wxDO_LOG_IF_ENABLED(Info) |
1219 | | #define wxVLogInfo(format, argptr) wxDO_LOGV(Info, format, argptr) |
1220 | | |
1221 | | |
1222 | | // this one is special as it only logs if we're in verbose mode |
1223 | | #define wxLogVerbose \ |
1224 | 0 | wxDO_IF(wxLOG_IS_ENABLED(Info) && wxLog::GetVerbose()) \ |
1225 | 0 | wxDO_LOG(Info) |
1226 | | |
1227 | | #define wxVLogVerbose(format, argptr) \ |
1228 | | wxDO_IF(wxLOG_IS_ENABLED(Info) && wxLog::GetVerbose()) \ |
1229 | | wxDO_LOGV(Info, format, argptr) |
1230 | | |
1231 | | // another special case: the level is passed as first argument of the function |
1232 | | // and so is not available to the macro |
1233 | | // |
1234 | | // notice that because of this, arguments of wxLogGeneric() are currently |
1235 | | // always evaluated, unlike for the other log functions |
1236 | | #define wxLogGeneric wxMAKE_LOGGER(Max).LogAtLevel |
1237 | | #define wxVLogGeneric(level, format, argptr) \ |
1238 | | wxDO_IF(wxLOG_IS_ENABLED(level)) \ |
1239 | | wxDO_LOGV(level, format, argptr) |
1240 | | |
1241 | | |
1242 | | // wxLogSysError() needs to stash the error code value in the log record info |
1243 | | // so it needs special handling too; additional complications arise because the |
1244 | | // error code may or not be present as the first argument |
1245 | | // |
1246 | | // notice that we unfortunately can't avoid the call to wxSysErrorCode() even |
1247 | | // though it may be unneeded if an explicit error code is passed to us because |
1248 | | // the message might not be logged immediately (e.g. it could be queued for |
1249 | | // logging from the main thread later) and so we can't to wait until it is |
1250 | | // logged to determine whether we have last error or not as it will be too late |
1251 | | // and it will have changed already by then (in fact it even changes when |
1252 | | // wxString::Format() is called because of vsnprintf() inside it so it can |
1253 | | // change even much sooner) |
1254 | 0 | #define wxLOG_KEY_SYS_ERROR_CODE "wx.sys_error" |
1255 | | |
1256 | | #define wxLogSysError \ |
1257 | 0 | wxDO_LOG_IF_ENABLED_WITH_FUNC(Error, MaybeStore(wxLOG_KEY_SYS_ERROR_CODE, \ |
1258 | 0 | wxSysErrorCode()).Log) |
1259 | | |
1260 | | // unfortunately we can't have overloaded macros so we can't define versions |
1261 | | // both with and without error code argument and have to rely on LogV() |
1262 | | // overloads in wxLogger to select between them |
1263 | | #define wxVLogSysError \ |
1264 | | wxMAKE_LOGGER(Error).MaybeStore(wxLOG_KEY_SYS_ERROR_CODE, \ |
1265 | | wxSysErrorCode()).LogV |
1266 | | |
1267 | | #if wxUSE_GUI |
1268 | | // wxLogStatus() is similar to wxLogSysError() as it allows to optionally |
1269 | | // specify the frame to which the message should go |
1270 | | #define wxLOG_KEY_FRAME "wx.frame" |
1271 | | |
1272 | | #define wxLogStatus \ |
1273 | | wxDO_LOG_IF_ENABLED_WITH_FUNC(Status, MaybeStore(wxLOG_KEY_FRAME).Log) |
1274 | | |
1275 | | #define wxVLogStatus \ |
1276 | | wxMAKE_LOGGER(Status).MaybeStore(wxLOG_KEY_FRAME).LogV |
1277 | | #endif // wxUSE_GUI |
1278 | | |
1279 | | |
1280 | | #else // !wxUSE_LOG |
1281 | | |
1282 | | #undef wxUSE_LOG_DEBUG |
1283 | | #define wxUSE_LOG_DEBUG 0 |
1284 | | |
1285 | | #undef wxUSE_LOG_TRACE |
1286 | | #define wxUSE_LOG_TRACE 0 |
1287 | | |
1288 | | // define macros for defining log functions which do nothing at all |
1289 | | #define wxDEFINE_EMPTY_LOG_FUNCTION(level) \ |
1290 | | template <typename... Targs> \ |
1291 | | void wxLog##level(const wxString& WXUNUSED(format), Targs...) { } \ |
1292 | | inline void wxVLog##level(const wxString& WXUNUSED(format), \ |
1293 | | va_list WXUNUSED(argptr)) { } \ |
1294 | | |
1295 | | #define wxDEFINE_EMPTY_LOG_FUNCTION2(level, argclass) \ |
1296 | | template <typename... Targs> \ |
1297 | | void wxLog##level(argclass WXUNUSED(arg), \ |
1298 | | const wxString& WXUNUSED(format), Targs...) { } \ |
1299 | | inline void wxVLog##level(argclass WXUNUSED(arg), \ |
1300 | | const wxString& WXUNUSED(format), \ |
1301 | | va_list WXUNUSED(argptr)) {} |
1302 | | |
1303 | | wxDEFINE_EMPTY_LOG_FUNCTION(FatalError); |
1304 | | wxDEFINE_EMPTY_LOG_FUNCTION(Error); |
1305 | | wxDEFINE_EMPTY_LOG_FUNCTION(SysError); |
1306 | | wxDEFINE_EMPTY_LOG_FUNCTION2(SysError, long); |
1307 | | wxDEFINE_EMPTY_LOG_FUNCTION(Warning); |
1308 | | wxDEFINE_EMPTY_LOG_FUNCTION(Message); |
1309 | | wxDEFINE_EMPTY_LOG_FUNCTION(Info); |
1310 | | wxDEFINE_EMPTY_LOG_FUNCTION(Verbose); |
1311 | | |
1312 | | wxDEFINE_EMPTY_LOG_FUNCTION2(Generic, wxLogLevel); |
1313 | | |
1314 | | #if wxUSE_GUI |
1315 | | wxDEFINE_EMPTY_LOG_FUNCTION(Status); |
1316 | | wxDEFINE_EMPTY_LOG_FUNCTION2(Status, wxFrame *); |
1317 | | #endif // wxUSE_GUI |
1318 | | |
1319 | | // Empty Class to fake wxLogNull |
1320 | | class WXDLLIMPEXP_BASE wxLogNull |
1321 | | { |
1322 | | public: |
1323 | | wxLogNull() = default; |
1324 | | }; |
1325 | | |
1326 | | // Dummy macros to replace some functions. |
1327 | | #define wxSysErrorCode() (unsigned long)0 |
1328 | | #define wxSysErrorMsg( X ) (const wxChar*)nullptr |
1329 | | #define wxSysErrorMsgStr( X ) wxEmptyString |
1330 | | |
1331 | | // Fake symbolic trace masks... for those that are used frequently |
1332 | | #define wxTRACE_OleCalls wxEmptyString // OLE interface calls |
1333 | | |
1334 | | #endif // wxUSE_LOG/!wxUSE_LOG |
1335 | | |
1336 | | |
1337 | | // debug functions can be completely disabled in optimized builds |
1338 | | |
1339 | | // if these log functions are disabled, we prefer to define them as (empty) |
1340 | | // variadic macros as this completely removes them and their argument |
1341 | | // evaluation from the object code but if this is not supported by compiler we |
1342 | | // use empty inline functions instead (defining them as nothing would result in |
1343 | | // compiler warnings) |
1344 | | // |
1345 | | // note that making wxVLogDebug/Trace() themselves (empty inline) functions is |
1346 | | // a bad idea as some compilers are stupid enough to not inline even empty |
1347 | | // functions if their parameters are complicated enough, but by defining them |
1348 | | // as an empty inline function we ensure that even dumbest compilers optimise |
1349 | | // them away |
1350 | 0 | inline void wxLogNop() { } |
1351 | | |
1352 | | #if wxUSE_LOG_DEBUG |
1353 | 722 | #define wxLogDebug wxDO_LOG_IF_ENABLED(Debug) |
1354 | | #define wxVLogDebug(format, argptr) wxDO_LOGV(Debug, format, argptr) |
1355 | | #else // !wxUSE_LOG_DEBUG |
1356 | | #define wxVLogDebug(fmt, valist) wxLogNop() |
1357 | | #define wxLogDebug(fmt, ...) wxLogNop() |
1358 | | #endif // wxUSE_LOG_DEBUG/!wxUSE_LOG_DEBUG |
1359 | | |
1360 | | #if wxUSE_LOG_TRACE |
1361 | 4 | #define wxLogTrace wxDO_LOG_IF_ENABLED_WITH_FUNC(Trace, LogTrace) |
1362 | | #define wxVLogTrace wxDO_LOG_IF_ENABLED_WITH_FUNC(Trace, LogVTrace) |
1363 | | #else // !wxUSE_LOG_TRACE |
1364 | | #define wxVLogTrace(mask, fmt, valist) wxLogNop() |
1365 | | #define wxLogTrace(mask, fmt, ...) wxLogNop() |
1366 | | #endif // wxUSE_LOG_TRACE/!wxUSE_LOG_TRACE |
1367 | | |
1368 | | // wxLogFatalError helper: show the (fatal) error to the user in a safe way, |
1369 | | // i.e. without using wxMessageBox() for example because it could crash |
1370 | | bool WXDLLIMPEXP_BASE |
1371 | | wxSafeShowMessage(const wxString& title, const wxString& text); |
1372 | | |
1373 | | // ---------------------------------------------------------------------------- |
1374 | | // debug only logging functions: use them with API name and error code |
1375 | | // ---------------------------------------------------------------------------- |
1376 | | |
1377 | | #if wxUSE_LOG_DEBUG |
1378 | | // make life easier for people using VC++ IDE: clicking on the message |
1379 | | // will take us immediately to the place of the failed API |
1380 | | #ifdef __VISUALC__ |
1381 | | #define wxLogApiError(api, rc) \ |
1382 | | wxLogDebug(wxT("%s(%d): '%s' failed with error 0x%08lx (%s)."), \ |
1383 | | __TFILE__, __LINE__, api, \ |
1384 | | (long)rc, wxSysErrorMsgStr(rc)) |
1385 | | #else // !VC++ |
1386 | | #define wxLogApiError(api, rc) \ |
1387 | 0 | wxLogDebug(wxT("In file %s at line %d: '%s' failed with ") \ |
1388 | 0 | wxT("error 0x%08lx (%s)."), \ |
1389 | 0 | __TFILE__, __LINE__, api, \ |
1390 | 0 | (long)rc, wxSysErrorMsgStr(rc)) |
1391 | | #endif // VC++/!VC++ |
1392 | | |
1393 | 0 | #define wxLogLastError(api) wxLogApiError(api, wxSysErrorCode()) |
1394 | | |
1395 | | #else // !wxUSE_LOG_DEBUG |
1396 | | #define wxLogApiError(api, err) wxLogNop() |
1397 | | #define wxLogLastError(api) wxLogNop() |
1398 | | #endif // wxUSE_LOG_DEBUG/!wxUSE_LOG_DEBUG |
1399 | | |
1400 | | // macro which disables debug logging in release builds: this is done by |
1401 | | // default by wxIMPLEMENT_APP() so usually it doesn't need to be used explicitly |
1402 | | #if defined(NDEBUG) && wxUSE_LOG_DEBUG |
1403 | | #define wxDISABLE_DEBUG_LOGGING_IN_RELEASE_BUILD() \ |
1404 | | wxLog::SetLogLevel(wxLOG_Info) |
1405 | | #else // !NDEBUG |
1406 | | #define wxDISABLE_DEBUG_LOGGING_IN_RELEASE_BUILD() |
1407 | | #endif // NDEBUG/!NDEBUG |
1408 | | |
1409 | | #endif // _WX_LOG_H_ |
1410 | | |