1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/log.cpp
3 // Purpose: Assorted wxLogXXX functions, and wxLog (sink for logs)
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 29/01/98
7 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22
23 #if wxUSE_LOG
24
25 // wxWidgets
26 #ifndef WX_PRECOMP
27 #include "wx/log.h"
28 #include "wx/app.h"
29 #include "wx/arrstr.h"
30 #include "wx/intl.h"
31 #include "wx/string.h"
32 #include "wx/utils.h"
33 #endif //WX_PRECOMP
34
35 #include "wx/apptrait.h"
36 #include "wx/datetime.h"
37 #include "wx/file.h"
38 #include "wx/msgout.h"
39 #include "wx/textfile.h"
40 #include "wx/thread.h"
41 #include "wx/private/threadinfo.h"
42 #include "wx/crt.h"
43 #include "wx/vector.h"
44
45 // other standard headers
46 #include <errno.h>
47
48 #include <string.h>
49
50 #include <stdlib.h>
51
52 #if defined(__WINDOWS__)
53 #include "wx/msw/private.h" // includes windows.h
54 #endif
55
56 #undef wxLOG_COMPONENT
57 const char *wxLOG_COMPONENT = "";
58
59 // this macro allows to define an object which will be initialized before any
60 // other function in this file is called: this is necessary to allow log
61 // functions to be used during static initialization (this is not advisable
62 // anyhow but we should at least try to not crash) and to also ensure that they
63 // are initialized by the time static initialization is done, i.e. before any
64 // threads are created hopefully
65 //
66 // the net effect of all this is that you can use Get##name() function to
67 // access the object without worrying about it being not initialized
68 //
69 // see also WX_DEFINE_GLOBAL_CONV2() in src/common/strconv.cpp
70 #define WX_DEFINE_GLOBAL_VAR(type, name) \
71 inline type& Get##name() \
72 { \
73 static type s_##name; \
74 return s_##name; \
75 } \
76 \
77 type *gs_##name##Ptr = &Get##name()
78
79 #if wxUSE_THREADS
80
81 namespace
82 {
83
84 // contains messages logged by the other threads and waiting to be shown until
85 // Flush() is called in the main one
86 typedef wxVector<wxLogRecord> wxLogRecords;
87 wxLogRecords gs_bufferedLogRecords;
88
89 #define WX_DEFINE_LOG_CS(name) WX_DEFINE_GLOBAL_VAR(wxCriticalSection, name##CS)
90
91 // this critical section is used for buffering the messages from threads other
92 // than main, i.e. it protects all accesses to gs_bufferedLogRecords above
93 WX_DEFINE_LOG_CS(BackgroundLog);
94
95 // this one is used for protecting TraceMasks() from concurrent access
96 WX_DEFINE_LOG_CS(TraceMask);
97
98 // and this one is used for GetComponentLevels()
99 WX_DEFINE_LOG_CS(Levels);
100
101 } // anonymous namespace
102
103 #endif // wxUSE_THREADS
104
105 // ----------------------------------------------------------------------------
106 // non member functions
107 // ----------------------------------------------------------------------------
108
109 // define this to enable wrapping of log messages
110 //#define LOG_PRETTY_WRAP
111
112 #ifdef LOG_PRETTY_WRAP
113 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
114 #endif
115
116 // ----------------------------------------------------------------------------
117 // module globals
118 // ----------------------------------------------------------------------------
119
120 namespace
121 {
122
123 // this struct is used to store information about the previous log message used
124 // by OnLog() to (optionally) avoid logging multiple copies of the same message
125 struct PreviousLogInfo
126 {
PreviousLogInfo__anon84e0d39a0211::PreviousLogInfo127 PreviousLogInfo()
128 {
129 numRepeated = 0;
130 }
131
132
133 // previous message itself
134 wxString msg;
135
136 // its level
137 wxLogLevel level;
138
139 // other information about it
140 wxLogRecordInfo info;
141
142 // the number of times it was already repeated
143 unsigned numRepeated;
144 };
145
146 PreviousLogInfo gs_prevLog;
147
148
149 // map containing all components for which log level was explicitly set
150 //
151 // NB: all accesses to it must be protected by GetLevelsCS() critical section
152 WX_DEFINE_GLOBAL_VAR(wxStringToNumHashMap, ComponentLevels);
153
154 // ----------------------------------------------------------------------------
155 // wxLogOutputBest: wxLog wrapper around wxMessageOutputBest
156 // ----------------------------------------------------------------------------
157
158 class wxLogOutputBest : public wxLog
159 {
160 public:
wxLogOutputBest()161 wxLogOutputBest() { }
162
163 protected:
DoLogText(const wxString & msg)164 virtual void DoLogText(const wxString& msg) wxOVERRIDE
165 {
166 wxMessageOutputBest().Output(msg);
167 }
168
169 private:
170 wxDECLARE_NO_COPY_CLASS(wxLogOutputBest);
171 };
172
173 } // anonymous namespace
174
175 // ============================================================================
176 // implementation
177 // ============================================================================
178
179 // ----------------------------------------------------------------------------
180 // helper global functions
181 // ----------------------------------------------------------------------------
182
wxSafeShowMessage(const wxString & title,const wxString & text)183 bool wxSafeShowMessage(const wxString& title, const wxString& text)
184 {
185 if ( !wxApp::GetValidTraits().SafeMessageBox(text, title) )
186 {
187 wxFprintf(stderr, wxS("%s: %s\n"), title.c_str(), text.c_str());
188 fflush(stderr);
189 return false;
190 }
191
192 // Message box actually shown.
193 return true;
194 }
195
196 // ----------------------------------------------------------------------------
197 // wxLogFormatter class implementation
198 // ----------------------------------------------------------------------------
199
200 #if WXWIN_COMPATIBILITY_3_0
201
202 // Special string used to check if FormatTime() is overridden: hopefully
203 // different from anything that could be reasonably returned by the overridden
204 // version without being as long as a GUID.
205 static const char* DEFAULT_FORMAT_TIME = "??";
206
207 wxString
FormatTime(time_t WXUNUSED (t)) const208 wxLogFormatter::FormatTime(time_t WXUNUSED(t)) const
209 {
210 return wxString::FromAscii(DEFAULT_FORMAT_TIME);
211 }
212
213 #endif // WXWIN_COMPATIBILITY_3_0
214
215 wxString
Format(wxLogLevel level,const wxString & msg,const wxLogRecordInfo & info) const216 wxLogFormatter::Format(wxLogLevel level,
217 const wxString& msg,
218 const wxLogRecordInfo& info) const
219 {
220 wxString prefix;
221
222 // don't time stamp debug messages under MSW as debug viewers usually
223 // already have an option to do it
224 #ifdef __WINDOWS__
225 if ( level != wxLOG_Debug && level != wxLOG_Trace )
226 #endif // __WINDOWS__
227 {
228 #if WXWIN_COMPATIBILITY_3_0
229 // Another backwards compatibility hack: check if FormatTime() was
230 // overridden in the user code.
231 prefix = FormatTime(info.timestamp);
232 if ( prefix == DEFAULT_FORMAT_TIME )
233 #endif // WXWIN_COMPATIBILITY_3_0
234 prefix = FormatTimeMS(info.timestampMS);
235 }
236
237 switch ( level )
238 {
239 case wxLOG_Error:
240 prefix += _("Error: ");
241 break;
242
243 case wxLOG_Warning:
244 prefix += _("Warning: ");
245 break;
246
247 // don't prepend "debug/trace" prefix under MSW as it goes to the debug
248 // window anyhow and so can't be confused with something else
249 #ifndef __WINDOWS__
250 case wxLOG_Debug:
251 // this prefix (as well as the one below) is intentionally not
252 // translated as nobody translates debug messages anyhow
253 prefix += "Debug: ";
254 break;
255
256 case wxLOG_Trace:
257 prefix += "Trace: ";
258 break;
259 #endif // !__WINDOWS__
260 }
261
262 return prefix + msg;
263 }
264
265 wxString
FormatTimeMS(wxLongLong_t msec) const266 wxLogFormatter::FormatTimeMS(wxLongLong_t msec) const
267 {
268 wxString str;
269
270 wxLog::TimeStampMS(&str, msec);
271
272 return str;
273 }
274
275
276 // ----------------------------------------------------------------------------
277 // wxLog class implementation
278 // ----------------------------------------------------------------------------
279
LogLastRepeatIfNeeded()280 unsigned wxLog::LogLastRepeatIfNeeded()
281 {
282 const unsigned count = gs_prevLog.numRepeated;
283
284 if ( gs_prevLog.numRepeated )
285 {
286 wxString msg;
287 #if wxUSE_INTL
288 if ( gs_prevLog.numRepeated == 1 )
289 {
290 // We use a separate message for this case as "repeated 1 time"
291 // looks somewhat strange.
292 msg = _("The previous message repeated once.");
293 }
294 else
295 {
296 // Notice that we still use wxPLURAL() to ensure that multiple
297 // numbers of times are correctly formatted, even though we never
298 // actually use the singular string.
299 msg.Printf(wxPLURAL("The previous message repeated %u time.",
300 "The previous message repeated %u times.",
301 gs_prevLog.numRepeated),
302 gs_prevLog.numRepeated);
303 }
304 #else
305 msg.Printf(wxS("The previous message was repeated %u time(s)."),
306 gs_prevLog.numRepeated);
307 #endif
308 gs_prevLog.numRepeated = 0;
309 gs_prevLog.msg.clear();
310 DoLogRecord(gs_prevLog.level, msg, gs_prevLog.info);
311 }
312
313 return count;
314 }
315
~wxLog()316 wxLog::~wxLog()
317 {
318 // Flush() must be called before destroying the object as otherwise some
319 // messages could be lost
320 if ( gs_prevLog.numRepeated )
321 {
322 wxMessageOutputDebug().Printf
323 (
324 #if wxUSE_INTL
325 wxPLURAL
326 (
327 "Last repeated message (\"%s\", %u time) wasn't output",
328 "Last repeated message (\"%s\", %u times) wasn't output",
329 gs_prevLog.numRepeated
330 ),
331 #else
332 wxS("Last repeated message (\"%s\", %u time(s)) wasn't output"),
333 #endif
334 gs_prevLog.msg,
335 gs_prevLog.numRepeated
336 );
337 }
338
339 delete m_formatter;
340 }
341
342 // ----------------------------------------------------------------------------
343 // wxLog logging functions
344 // ----------------------------------------------------------------------------
345
346 /* static */
347 void
OnLog(wxLogLevel level,const wxString & msg,time_t t)348 wxLog::OnLog(wxLogLevel level, const wxString& msg, time_t t)
349 {
350 wxLogRecordInfo info;
351 info.timestampMS = 1000*t;
352 #if wxUSE_THREADS
353 info.threadId = wxThread::GetCurrentId();
354 #endif // wxUSE_THREADS
355
356 OnLog(level, msg, info);
357 }
358
359 /* static */
360 void
OnLog(wxLogLevel level,const wxString & msg,const wxLogRecordInfo & info)361 wxLog::OnLog(wxLogLevel level,
362 const wxString& msg,
363 const wxLogRecordInfo& info)
364 {
365 // fatal errors can't be suppressed nor handled by the custom log target
366 // and always terminate the program
367 if ( level == wxLOG_FatalError )
368 {
369 wxSafeShowMessage(wxS("Fatal Error"), msg);
370
371 wxAbort();
372 }
373
374 wxLog *logger;
375
376 #if wxUSE_THREADS
377 if ( !wxThread::IsMain() )
378 {
379 logger = wxThreadInfo.logger;
380 if ( !logger )
381 {
382 if ( ms_pLogger )
383 {
384 // buffer the messages until they can be shown from the main
385 // thread
386 wxCriticalSectionLocker lock(GetBackgroundLogCS());
387
388 gs_bufferedLogRecords.push_back(wxLogRecord(level, msg, info));
389
390 // ensure that our Flush() will be called soon
391 wxWakeUpIdle();
392 }
393 //else: we don't have any logger at all, there is no need to log
394 // anything
395
396 return;
397 }
398 //else: we have a thread-specific logger, we can send messages to it
399 // directly
400 }
401 else
402 #endif // wxUSE_THREADS
403 {
404 logger = GetMainThreadActiveTarget();
405 if ( !logger )
406 return;
407 }
408
409 logger->CallDoLogNow(level, msg, info);
410 }
411
412 void
CallDoLogNow(wxLogLevel level,const wxString & msg,const wxLogRecordInfo & info)413 wxLog::CallDoLogNow(wxLogLevel level,
414 const wxString& msg,
415 const wxLogRecordInfo& info)
416 {
417 if ( GetRepetitionCounting() )
418 {
419 if ( msg == gs_prevLog.msg )
420 {
421 gs_prevLog.numRepeated++;
422
423 // nothing else to do, in particular, don't log the
424 // repeated message
425 return;
426 }
427
428 LogLastRepeatIfNeeded();
429
430 // reset repetition counter for a new message
431 gs_prevLog.msg = msg;
432 gs_prevLog.level = level;
433 gs_prevLog.info = info;
434 }
435
436 // handle extra data which may be passed to us by wxLogXXX()
437 wxString prefix, suffix;
438 wxUIntPtr num = 0;
439 if ( info.GetNumValue(wxLOG_KEY_SYS_ERROR_CODE, &num) )
440 {
441 const long err = static_cast<long>(num);
442
443 suffix.Printf(_(" (error %ld: %s)"), err, wxSysErrorMsgStr(err));
444 }
445
446 #if wxUSE_LOG_TRACE
447 wxString str;
448 if ( level == wxLOG_Trace && info.GetStrValue(wxLOG_KEY_TRACE_MASK, &str) )
449 {
450 prefix = "(" + str + ") ";
451 }
452 #endif // wxUSE_LOG_TRACE
453
454 DoLogRecord(level, prefix + msg + suffix, info);
455 }
456
DoLogRecord(wxLogLevel level,const wxString & msg,const wxLogRecordInfo & info)457 void wxLog::DoLogRecord(wxLogLevel level,
458 const wxString& msg,
459 const wxLogRecordInfo& info)
460 {
461 #if WXWIN_COMPATIBILITY_2_8
462 // call the old DoLog() to ensure that existing custom log classes still
463 // work
464 //
465 // as the user code could have defined it as either taking "const char *"
466 // (in ANSI build) or "const wxChar *" (in ANSI/Unicode), we have no choice
467 // but to call both of them
468 DoLog(level, (const char*)msg.mb_str(), info.timestamp);
469 DoLog(level, (const wchar_t*)msg.wc_str(), info.timestamp);
470 #else // !WXWIN_COMPATIBILITY_2_8
471 wxUnusedVar(info);
472 #endif // WXWIN_COMPATIBILITY_2_8/!WXWIN_COMPATIBILITY_2_8
473
474 // Use wxLogFormatter to format the message
475 DoLogTextAtLevel(level, m_formatter->Format (level, msg, info));
476 }
477
DoLogTextAtLevel(wxLogLevel level,const wxString & msg)478 void wxLog::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
479 {
480 // we know about debug messages (because using wxMessageOutputDebug is the
481 // right thing to do in 99% of all cases and also for compatibility) but
482 // anything else needs to be handled in the derived class
483 if ( level == wxLOG_Debug || level == wxLOG_Trace )
484 {
485 wxMessageOutputDebug().Output(msg + wxS('\n'));
486 }
487 else
488 {
489 DoLogText(msg);
490 }
491 }
492
DoLogText(const wxString & WXUNUSED (msg))493 void wxLog::DoLogText(const wxString& WXUNUSED(msg))
494 {
495 // in 2.8-compatible build the derived class might override DoLog() or
496 // DoLogString() instead so we can't have this assert there
497 #if !WXWIN_COMPATIBILITY_2_8
498 wxFAIL_MSG( "must be overridden if it is called" );
499 #endif // WXWIN_COMPATIBILITY_2_8
500 }
501
502 #if WXWIN_COMPATIBILITY_2_8
503
DoLog(wxLogLevel WXUNUSED (level),const char * szString,time_t t)504 void wxLog::DoLog(wxLogLevel WXUNUSED(level), const char *szString, time_t t)
505 {
506 DoLogString(szString, t);
507 }
508
DoLog(wxLogLevel WXUNUSED (level),const wchar_t * wzString,time_t t)509 void wxLog::DoLog(wxLogLevel WXUNUSED(level), const wchar_t *wzString, time_t t)
510 {
511 DoLogString(wzString, t);
512 }
513
514 #endif // WXWIN_COMPATIBILITY_2_8
515
516 // ----------------------------------------------------------------------------
517 // wxLog active target management
518 // ----------------------------------------------------------------------------
519
GetActiveTarget()520 wxLog *wxLog::GetActiveTarget()
521 {
522 #if wxUSE_THREADS
523 if ( !wxThread::IsMain() )
524 {
525 // check if we have a thread-specific log target
526 wxLog * const logger = wxThreadInfo.logger;
527
528 // the code below should be only executed for the main thread as
529 // CreateLogTarget() is not meant for auto-creating log targets for
530 // worker threads so skip it in any case
531 return logger ? logger : ms_pLogger;
532 }
533 #endif // wxUSE_THREADS
534
535 return GetMainThreadActiveTarget();
536 }
537
538 /* static */
GetMainThreadActiveTarget()539 wxLog *wxLog::GetMainThreadActiveTarget()
540 {
541 if ( ms_bAutoCreate && ms_pLogger == NULL ) {
542 // prevent infinite recursion if someone calls wxLogXXX() from
543 // wxApp::CreateLogTarget()
544 static bool s_bInGetActiveTarget = false;
545 if ( !s_bInGetActiveTarget ) {
546 s_bInGetActiveTarget = true;
547
548 // ask the application to create a log target for us
549 if ( wxTheApp != NULL )
550 ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget();
551 else
552 ms_pLogger = new wxLogOutputBest;
553
554 s_bInGetActiveTarget = false;
555
556 // do nothing if it fails - what can we do?
557 }
558 }
559
560 return ms_pLogger;
561 }
562
SetActiveTarget(wxLog * pLogger)563 wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
564 {
565 if ( ms_pLogger != NULL ) {
566 // flush the old messages before changing because otherwise they might
567 // get lost later if this target is not restored
568 ms_pLogger->Flush();
569 }
570
571 wxLog *pOldLogger = ms_pLogger;
572 ms_pLogger = pLogger;
573
574 return pOldLogger;
575 }
576
577 #if wxUSE_THREADS
578 /* static */
SetThreadActiveTarget(wxLog * logger)579 wxLog *wxLog::SetThreadActiveTarget(wxLog *logger)
580 {
581 wxASSERT_MSG( !wxThread::IsMain(), "use SetActiveTarget() for main thread" );
582
583 wxLog * const oldLogger = wxThreadInfo.logger;
584 if ( oldLogger )
585 oldLogger->Flush();
586
587 wxThreadInfo.logger = logger;
588
589 return oldLogger;
590 }
591 #endif // wxUSE_THREADS
592
DontCreateOnDemand()593 void wxLog::DontCreateOnDemand()
594 {
595 ms_bAutoCreate = false;
596
597 // this is usually called at the end of the program and we assume that it
598 // is *always* called at the end - so we free memory here to avoid false
599 // memory leak reports from wxWin memory tracking code
600 ClearTraceMasks();
601 }
602
DoCreateOnDemand()603 void wxLog::DoCreateOnDemand()
604 {
605 ms_bAutoCreate = true;
606 }
607
608 // ----------------------------------------------------------------------------
609 // wxLog components levels
610 // ----------------------------------------------------------------------------
611
612 /* static */
SetComponentLevel(const wxString & component,wxLogLevel level)613 void wxLog::SetComponentLevel(const wxString& component, wxLogLevel level)
614 {
615 if ( component.empty() )
616 {
617 SetLogLevel(level);
618 }
619 else
620 {
621 wxCRIT_SECT_LOCKER(lock, GetLevelsCS());
622
623 GetComponentLevels()[component] = level;
624 }
625 }
626
627 /* static */
GetComponentLevel(const wxString & componentOrig)628 wxLogLevel wxLog::GetComponentLevel(const wxString& componentOrig)
629 {
630 wxCRIT_SECT_LOCKER(lock, GetLevelsCS());
631
632 // Make a copy before modifying it in the loop.
633 wxString component = componentOrig;
634
635 const wxStringToNumHashMap& componentLevels = GetComponentLevels();
636 while ( !component.empty() )
637 {
638 wxStringToNumHashMap::const_iterator
639 it = componentLevels.find(component);
640 if ( it != componentLevels.end() )
641 return static_cast<wxLogLevel>(it->second);
642
643 component = component.BeforeLast('/');
644 }
645
646 return GetLogLevel();
647 }
648
649 // ----------------------------------------------------------------------------
650 // wxLog trace masks
651 // ----------------------------------------------------------------------------
652
653 namespace
654 {
655
656 // because IsAllowedTraceMask() may be called during static initialization
657 // (this is not recommended but it may still happen, see #11592) we can't use a
658 // simple static variable which might be not initialized itself just yet to
659 // store the trace masks, but need this accessor function which will ensure
660 // that the variable is always correctly initialized before being accessed
661 //
662 // notice that this doesn't make accessing it MT-safe, of course, you need to
663 // serialize accesses to it using GetTraceMaskCS() for this
TraceMasks()664 wxArrayString& TraceMasks()
665 {
666 static wxArrayString s_traceMasks;
667
668 return s_traceMasks;
669 }
670
671 } // anonymous namespace
672
GetTraceMasks()673 /* static */ const wxArrayString& wxLog::GetTraceMasks()
674 {
675 // because of this function signature (it returns a reference, not the
676 // object), it is inherently MT-unsafe so there is no need to acquire the
677 // lock here anyhow
678
679 return TraceMasks();
680 }
681
AddTraceMask(const wxString & str)682 void wxLog::AddTraceMask(const wxString& str)
683 {
684 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
685
686 TraceMasks().push_back(str);
687 }
688
RemoveTraceMask(const wxString & str)689 void wxLog::RemoveTraceMask(const wxString& str)
690 {
691 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
692
693 int index = TraceMasks().Index(str);
694 if ( index != wxNOT_FOUND )
695 TraceMasks().RemoveAt((size_t)index);
696 }
697
ClearTraceMasks()698 void wxLog::ClearTraceMasks()
699 {
700 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
701
702 TraceMasks().Clear();
703 }
704
IsAllowedTraceMask(const wxString & mask)705 /*static*/ bool wxLog::IsAllowedTraceMask(const wxString& mask)
706 {
707 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
708
709 const wxArrayString& masks = GetTraceMasks();
710 for ( wxArrayString::const_iterator it = masks.begin(),
711 en = masks.end();
712 it != en;
713 ++it )
714 {
715 if ( *it == mask)
716 return true;
717 }
718
719 return false;
720 }
721
722 // ----------------------------------------------------------------------------
723 // wxLog miscellaneous other methods
724 // ----------------------------------------------------------------------------
725
726 #if wxUSE_DATETIME
727
TimeStamp(wxString * str)728 void wxLog::TimeStamp(wxString *str)
729 {
730 if ( !ms_timestamp.empty() )
731 {
732 *str = wxDateTime::UNow().Format(ms_timestamp);
733 *str += wxS(": ");
734 }
735 }
736
TimeStamp(wxString * str,time_t t)737 void wxLog::TimeStamp(wxString *str, time_t t)
738 {
739 if ( !ms_timestamp.empty() )
740 {
741 *str = wxDateTime(t).Format(ms_timestamp);
742 *str += wxS(": ");
743 }
744 }
745
TimeStampMS(wxString * str,wxLongLong_t msec)746 void wxLog::TimeStampMS(wxString *str, wxLongLong_t msec)
747 {
748 if ( !ms_timestamp.empty() )
749 {
750 *str = wxDateTime(wxLongLong(msec)).Format(wxLog::GetTimestamp());
751 *str += wxS(": ");
752 }
753 }
754
755 #else // !wxUSE_DATETIME
756
TimeStamp(wxString *)757 void wxLog::TimeStamp(wxString*)
758 {
759 }
760
TimeStamp(wxString *,time_t)761 void wxLog::TimeStamp(wxString*, time_t)
762 {
763 }
764
TimeStampMS(wxString *,wxLongLong_t)765 void wxLog::TimeStampMS(wxString*, wxLongLong_t)
766 {
767 }
768
769 #endif // wxUSE_DATETIME/!wxUSE_DATETIME
770
771 #if wxUSE_THREADS
772
FlushThreadMessages()773 void wxLog::FlushThreadMessages()
774 {
775 // check if we have queued messages from other threads
776 wxLogRecords bufferedLogRecords;
777
778 {
779 wxCriticalSectionLocker lock(GetBackgroundLogCS());
780 bufferedLogRecords.swap(gs_bufferedLogRecords);
781
782 // release the lock now to not keep it while we are logging the
783 // messages below, allowing background threads to run
784 }
785
786 if ( !bufferedLogRecords.empty() )
787 {
788 for ( wxLogRecords::const_iterator it = bufferedLogRecords.begin();
789 it != bufferedLogRecords.end();
790 ++it )
791 {
792 CallDoLogNow(it->level, it->msg, it->info);
793 }
794 }
795 }
796
797 /* static */
IsThreadLoggingEnabled()798 bool wxLog::IsThreadLoggingEnabled()
799 {
800 return !wxThreadInfo.loggingDisabled;
801 }
802
803 /* static */
EnableThreadLogging(bool enable)804 bool wxLog::EnableThreadLogging(bool enable)
805 {
806 const bool wasEnabled = !wxThreadInfo.loggingDisabled;
807 wxThreadInfo.loggingDisabled = !enable;
808 return wasEnabled;
809 }
810
811 #endif // wxUSE_THREADS
812
SetFormatter(wxLogFormatter * formatter)813 wxLogFormatter *wxLog::SetFormatter(wxLogFormatter* formatter)
814 {
815 wxLogFormatter* formatterOld = m_formatter;
816 m_formatter = formatter ? formatter : new wxLogFormatter;
817
818 return formatterOld;
819 }
820
Flush()821 void wxLog::Flush()
822 {
823 LogLastRepeatIfNeeded();
824 }
825
826 /* static */
FlushActive()827 void wxLog::FlushActive()
828 {
829 if ( ms_suspendCount )
830 return;
831
832 wxLog * const log = GetActiveTarget();
833 if ( log )
834 {
835 #if wxUSE_THREADS
836 if ( wxThread::IsMain() )
837 log->FlushThreadMessages();
838 #endif // wxUSE_THREADS
839
840 log->Flush();
841 }
842 }
843
844 // ----------------------------------------------------------------------------
845 // wxLogBuffer implementation
846 // ----------------------------------------------------------------------------
847
Flush()848 void wxLogBuffer::Flush()
849 {
850 wxLog::Flush();
851
852 if ( !m_str.empty() )
853 {
854 wxMessageOutputBest out;
855 out.Printf(wxS("%s"), m_str.c_str());
856 m_str.clear();
857 }
858 }
859
DoLogTextAtLevel(wxLogLevel level,const wxString & msg)860 void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
861 {
862 // don't put debug messages in the buffer, we don't want to show
863 // them to the user in a msg box, log them immediately
864 switch ( level )
865 {
866 case wxLOG_Debug:
867 case wxLOG_Trace:
868 wxLog::DoLogTextAtLevel(level, msg);
869 break;
870
871 default:
872 m_str << msg << wxS("\n");
873 }
874 }
875
876 // ----------------------------------------------------------------------------
877 // wxLogStderr class implementation
878 // ----------------------------------------------------------------------------
879
wxLogStderr(FILE * fp,const wxMBConv & conv)880 wxLogStderr::wxLogStderr(FILE *fp, const wxMBConv& conv)
881 : wxMessageOutputStderr(fp ? fp : stderr, conv)
882 {
883 }
884
DoLogText(const wxString & msg)885 void wxLogStderr::DoLogText(const wxString& msg)
886 {
887 // First send it to stderr, even if we don't have it (e.g. in a Windows GUI
888 // application under) it's not a problem to try to use it and it's easier
889 // than determining whether we do have it or not.
890 wxMessageOutputStderr::Output(msg);
891
892 // under GUI systems such as Windows or Mac, programs usually don't have
893 // stderr at all, so show the messages also somewhere else, typically in
894 // the debugger window so that they go at least somewhere instead of being
895 // simply lost
896 if ( m_fp == stderr )
897 {
898 wxAppTraits *traits = wxApp::GetTraitsIfExists();
899 if ( traits && !traits->HasStderr() )
900 {
901 wxMessageOutputDebug().Output(msg + wxS('\n'));
902 }
903 }
904 }
905
906 // ----------------------------------------------------------------------------
907 // wxLogStream implementation
908 // ----------------------------------------------------------------------------
909
910 #if wxUSE_STD_IOSTREAM
911 #include "wx/ioswrap.h"
wxLogStream(wxSTD ostream * ostr,const wxMBConv & conv)912 wxLogStream::wxLogStream(wxSTD ostream *ostr, const wxMBConv& conv)
913 : wxMessageOutputWithConv(conv)
914 {
915 if ( ostr == NULL )
916 m_ostr = &wxSTD cerr;
917 else
918 m_ostr = ostr;
919 }
920
DoLogText(const wxString & msg)921 void wxLogStream::DoLogText(const wxString& msg)
922 {
923 const wxCharBuffer& buf = PrepareForOutput(msg);
924 m_ostr->write(buf, buf.length());
925 }
926 #endif // wxUSE_STD_IOSTREAM
927
928 // ----------------------------------------------------------------------------
929 // wxLogChain
930 // ----------------------------------------------------------------------------
931
wxLogChain(wxLog * logger)932 wxLogChain::wxLogChain(wxLog *logger)
933 {
934 m_bPassMessages = true;
935
936 m_logNew = logger;
937
938 // Notice that we use GetActiveTarget() here instead of directly calling
939 // SetActiveTarget() to trigger wxLog auto-creation: if we're created as
940 // the first logger, we should still chain with the standard, implicit and
941 // possibly still not created standard logger instead of disabling normal
942 // logging entirely.
943 m_logOld = wxLog::GetActiveTarget();
944 wxLog::SetActiveTarget(this);
945 }
946
~wxLogChain()947 wxLogChain::~wxLogChain()
948 {
949 wxLog::SetActiveTarget(m_logOld);
950
951 if ( m_logNew != this )
952 delete m_logNew;
953 }
954
SetLog(wxLog * logger)955 void wxLogChain::SetLog(wxLog *logger)
956 {
957 if ( m_logNew != this )
958 delete m_logNew;
959
960 m_logNew = logger;
961 }
962
Flush()963 void wxLogChain::Flush()
964 {
965 if ( m_logOld )
966 m_logOld->Flush();
967
968 // be careful to avoid infinite recursion
969 if ( m_logNew && m_logNew != this )
970 m_logNew->Flush();
971 }
972
DoLogRecord(wxLogLevel level,const wxString & msg,const wxLogRecordInfo & info)973 void wxLogChain::DoLogRecord(wxLogLevel level,
974 const wxString& msg,
975 const wxLogRecordInfo& info)
976 {
977 // let the previous logger show it
978 if ( m_logOld && IsPassingMessages() )
979 m_logOld->LogRecord(level, msg, info);
980
981 // and also send it to the new one
982 if ( m_logNew )
983 {
984 // don't call m_logNew->LogRecord() to avoid infinite recursion when
985 // m_logNew is this object itself
986 if ( m_logNew != this )
987 m_logNew->LogRecord(level, msg, info);
988 else
989 wxLog::DoLogRecord(level, msg, info);
990 }
991 }
992
993 #ifdef __VISUALC__
994 // "'this' : used in base member initializer list" - so what?
995 #pragma warning(disable:4355)
996 #endif // VC++
997
998 // ----------------------------------------------------------------------------
999 // wxLogInterposer
1000 // ----------------------------------------------------------------------------
1001
wxLogInterposer()1002 wxLogInterposer::wxLogInterposer()
1003 : wxLogChain(this)
1004 {
1005 }
1006
1007 // ----------------------------------------------------------------------------
1008 // wxLogInterposerTemp
1009 // ----------------------------------------------------------------------------
1010
wxLogInterposerTemp()1011 wxLogInterposerTemp::wxLogInterposerTemp()
1012 : wxLogChain(this)
1013 {
1014 DetachOldLog();
1015 }
1016
1017 #ifdef __VISUALC__
1018 #pragma warning(default:4355)
1019 #endif // VC++
1020
1021 // ============================================================================
1022 // Global functions/variables
1023 // ============================================================================
1024
1025 // ----------------------------------------------------------------------------
1026 // static variables
1027 // ----------------------------------------------------------------------------
1028
1029 bool wxLog::ms_bRepetCounting = false;
1030
1031 wxLog *wxLog::ms_pLogger = NULL;
1032 bool wxLog::ms_doLog = true;
1033 bool wxLog::ms_bAutoCreate = true;
1034 bool wxLog::ms_bVerbose = false;
1035
1036 wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default
1037
1038 size_t wxLog::ms_suspendCount = 0;
1039
1040 wxString wxLog::ms_timestamp(wxS("%X")); // time only, no date
1041
1042 #if WXWIN_COMPATIBILITY_2_8
1043 wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0;
1044 #endif // wxDEBUG_LEVEL
1045
1046 // ----------------------------------------------------------------------------
1047 // stdout error logging helper
1048 // ----------------------------------------------------------------------------
1049
1050 // helper function: wraps the message and justifies it under given position
1051 // (looks more pretty on the terminal). Also adds newline at the end.
1052 //
1053 // TODO this is now disabled until I find a portable way of determining the
1054 // terminal window size (ok, I found it but does anybody really cares?)
1055 #ifdef LOG_PRETTY_WRAP
wxLogWrap(FILE * f,const char * pszPrefix,const char * psz)1056 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
1057 {
1058 size_t nMax = 80; // FIXME
1059 size_t nStart = strlen(pszPrefix);
1060 fputs(pszPrefix, f);
1061
1062 size_t n;
1063 while ( *psz != '\0' ) {
1064 for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
1065 putc(*psz++, f);
1066
1067 // wrapped?
1068 if ( *psz != '\0' ) {
1069 /*putc('\n', f);*/
1070 for ( n = 0; n < nStart; n++ )
1071 putc(' ', f);
1072
1073 // as we wrapped, squeeze all white space
1074 while ( isspace(*psz) )
1075 psz++;
1076 }
1077 }
1078
1079 putc('\n', f);
1080 }
1081 #endif //LOG_PRETTY_WRAP
1082
1083 // ----------------------------------------------------------------------------
1084 // error code/error message retrieval functions
1085 // ----------------------------------------------------------------------------
1086
1087 // get error code from syste
wxSysErrorCode()1088 unsigned long wxSysErrorCode()
1089 {
1090 #if defined(__WINDOWS__)
1091 return ::GetLastError();
1092 #else //Unix
1093 return errno;
1094 #endif //Win/Unix
1095 }
1096
1097 #if defined(__WINDOWS__)
1098
wxMSWFormatMessage(DWORD nErrCode,HMODULE hModule)1099 wxString wxMSWFormatMessage(DWORD nErrCode, HMODULE hModule)
1100 {
1101 DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
1102 FORMAT_MESSAGE_FROM_SYSTEM |
1103 FORMAT_MESSAGE_IGNORE_INSERTS;
1104 if ( hModule )
1105 flags |= FORMAT_MESSAGE_FROM_HMODULE;
1106
1107 // get error message from system
1108 LPVOID lpMsgBuf;
1109 if ( ::FormatMessage
1110 (
1111 flags,
1112 hModule,
1113 nErrCode,
1114 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1115 (LPTSTR)&lpMsgBuf,
1116 0,
1117 NULL
1118 ) == 0 )
1119 {
1120 wxLogDebug(wxS("FormatMessage failed with error 0x%lx"), GetLastError());
1121
1122 // if this happens, something is seriously wrong, so don't use _() here
1123 // for safety
1124 return wxString::Format(wxS("unknown error 0x%lx"), nErrCode);
1125 }
1126
1127 wxString str;
1128
1129 // copy it to our buffer and free memory
1130 // Crashes on SmartPhone (FIXME)
1131 if( lpMsgBuf != 0 )
1132 {
1133 str = static_cast<const wxChar *>(lpMsgBuf);
1134
1135 LocalFree(lpMsgBuf);
1136
1137 // returned string is ended with '\r\n' - bad
1138 size_t len = str.length();
1139 if ( len >= 2 ) {
1140 // truncate string
1141 if ( str[len - 2] == wxS('\r') )
1142 str.Truncate(len - 2);
1143 }
1144 }
1145
1146 return str;
1147 }
1148
1149 #endif // __WINDOWS__
1150
wxSysErrorMsgStr(unsigned long nErrCode)1151 wxString wxSysErrorMsgStr(unsigned long nErrCode)
1152 {
1153 if ( nErrCode == 0 )
1154 nErrCode = wxSysErrorCode();
1155
1156 #if defined(__WINDOWS__)
1157 return wxMSWFormatMessage(nErrCode);
1158 #else // !__WINDOWS__
1159 char buffer[1024];
1160 char *errorMsg = buffer;
1161
1162 // We use the same unsigned long type under all platforms, but under
1163 // Unix the error code is just int.
1164 const int errorCode = static_cast<int>(nErrCode);
1165
1166 #if defined(__GLIBC__) && defined(_GNU_SOURCE) // GNU-specific strerror_r
1167 // GNU's strerror_r has a weird interface -- it doesn't
1168 // necessarily copy anything to the buffer given; use return
1169 // value instead.
1170 errorMsg = strerror_r(errorCode, buffer, sizeof(buffer));
1171 #elif defined( __VMS )
1172 errorMsg = strerror(errorCode);
1173 #else // XSI-compliant strerror_r
1174 strerror_r(errorCode, buffer, sizeof(buffer));
1175 #endif
1176
1177 // at this point errorMsg might not point to buffer anymore
1178 return errorMsg;
1179 #endif // __WINDOWS__/!__WINDOWS__
1180 }
1181
1182 // get error message from system as a char pointer: this function has to use a
1183 // static buffer of fixed size, so should be avoided in favour of the function
1184 // returning wxString
wxSysErrorMsg(unsigned long nErrCode)1185 const wxChar *wxSysErrorMsg(unsigned long nErrCode)
1186 {
1187 static wxChar s_szBuf[1024];
1188 wxStrlcpy(s_szBuf, (const wxChar*)wxSysErrorMsgStr(nErrCode).c_str(),
1189 WXSIZEOF(s_szBuf));
1190 return s_szBuf;
1191 }
1192
1193 #endif // wxUSE_LOG
1194