Coverage Report

Created: 2025-07-23 07:02

/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