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