]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: log.h | |
3 | // Purpose: topic overview | |
4 | // Author: wxWidgets team | |
5 | // Licence: wxWindows licence | |
6 | ///////////////////////////////////////////////////////////////////////////// | |
7 | ||
8 | /** | |
9 | ||
10 | @page overview_log Logging Overview | |
11 | ||
12 | @tableofcontents | |
13 | ||
14 | This is a general overview of logging classes provided by wxWidgets. The word | |
15 | logging here has a broad sense, including all of the program output, not only | |
16 | non-interactive messages. The logging facilities included in wxWidgets provide | |
17 | the base wxLog class which defines the standard interface for a @e log target | |
18 | as well as several standard implementations of it and a family of functions to | |
19 | use with them. | |
20 | ||
21 | First of all, no knowledge of wxLog classes is needed to use them. For this, | |
22 | you should only know about @ref group_funcmacro_log "wxLogXXX() functions". | |
23 | All of them have the same syntax as @e printf() or @e vprintf() , i.e. they | |
24 | take the format string as the first argument and respectively a variable number | |
25 | of arguments or a variable argument list pointer. Here are all of them: | |
26 | ||
27 | @li wxLogFatalError() which is like wxLogError(), but also terminates the program | |
28 | with the exit code 3 (using @e abort() standard function). Unlike for all | |
29 | the other logging functions, this function can't be overridden by a log | |
30 | target. | |
31 | @li wxLogError() is the function to use for error messages, i.e. the messages | |
32 | that must be shown to the user. The default processing is to pop up a | |
33 | message box to inform the user about it. | |
34 | @li wxLogWarning() for warnings. They are also normally shown to the user, but | |
35 | don't interrupt the program work. | |
36 | @li wxLogMessage() is for all normal, informational messages. They also appear in | |
37 | a message box by default (but it can be changed, see below). | |
38 | @li wxLogVerbose() is for verbose output. Normally, it is suppressed, but might | |
39 | be activated if the user wishes to know more details about the program | |
40 | progress (another, but possibly confusing name for the same function is | |
41 | wxLogInfo). | |
42 | @li wxLogStatus() is for status messages. They will go into the status bar of the | |
43 | active or specified (as the first argument) wxFrame if it has one. | |
44 | @li wxLogSysError() is mostly used by wxWidgets itself, but might be handy for | |
45 | logging errors after system call (API function) failure. It logs the | |
46 | specified message text as well as the last system error code (@e errno or | |
47 | Windows' @e GetLastError() depending on the platform) and the corresponding error | |
48 | message. The second form of this function takes the error code explicitly | |
49 | as the first argument. | |
50 | @li wxLogDebug() is @b the right function for debug output. It only does anything | |
51 | at all in the debug mode (when the preprocessor symbol @c __WXDEBUG__ is | |
52 | defined) and expands to nothing in release mode (otherwise). | |
53 | Note that under Windows, you must either run the program under debugger or | |
54 | use a 3rd party program such as DebugView | |
55 | (http://www.microsoft.com/technet/sysinternals/Miscellaneous/DebugView.mspx) | |
56 | to actually see the debug output. | |
57 | @li wxLogTrace() as wxLogDebug() only does something in debug build. The reason for | |
58 | making it a separate function from it is that usually there are a lot of | |
59 | trace messages, so it might make sense to separate them from other debug | |
60 | messages which would be flooded in them. Moreover, the second version of | |
61 | this function takes a trace mask as the first argument which allows to | |
62 | further restrict the amount of messages generated. | |
63 | ||
64 | @see @ref group_funcmacro_log "Logging Functions and Macros" | |
65 | ||
66 | The usage of these functions should be fairly straightforward, however it may | |
67 | be asked why not use the other logging facilities, such as C standard stdio | |
68 | functions or C++ streams. The short answer is that they're all very good | |
69 | generic mechanisms, but are not really adapted for wxWidgets, while the log | |
70 | classes are. Some of advantages in using wxWidgets log functions are: | |
71 | ||
72 | @li @b Portability: It is a common practice to use @e printf() statements or | |
73 | cout/cerr C++ streams for writing out some (debug or otherwise) | |
74 | information. Although it works just fine under Unix, these messages go | |
75 | strictly nowhere under Windows where the stdout of GUI programs is not | |
76 | assigned to anything. Thus, you might view wxLogMessage() as a simple | |
77 | substitute for @e printf(). | |
78 | You can also redirect the @e wxLogXXX calls to @e cout by just writing: | |
79 | @code | |
80 | wxLog* logger = new wxLogStream(&cout); | |
81 | wxLog::SetActiveTarget(logger); | |
82 | @endcode | |
83 | Finally, there is also a possibility to redirect the output sent to @e cout | |
84 | to a wxTextCtrl by using the wxStreamToTextRedirector class. | |
85 | @li @b Flexibility: The output of wxLog functions can be redirected or | |
86 | suppressed entirely based on their importance, which is either impossible | |
87 | or difficult to do with traditional methods. For example, only error | |
88 | messages, or only error messages and warnings might be logged, filtering | |
89 | out all informational messages. | |
90 | @li @b Completeness: Usually, an error message should be presented to the user | |
91 | when some operation fails. Let's take a quite simple but common case of a | |
92 | file error: suppose that you're writing your data file on disk and there is | |
93 | not enough space. The actual error might have been detected inside | |
94 | wxWidgets code (say, in wxFile::Write), so the calling function doesn't | |
95 | really know the exact reason of the failure, it only knows that the data | |
96 | file couldn't be written to the disk. However, as wxWidgets uses | |
97 | wxLogError() in this situation, the exact error code (and the corresponding | |
98 | error message) will be given to the user together with "high level" message | |
99 | about data file writing error. | |
100 | ||
101 | ||
102 | ||
103 | @section overview_log_enable Log Messages Selection | |
104 | ||
105 | By default, most log messages are enabled. In particular, this means that | |
106 | errors logged by wxWidgets code itself (e.g. when it fails to perform some | |
107 | operation, for instance wxFile::Open() logs an error when it fails to open a | |
108 | file) will be processed and shown to the user. To disable the logging entirely | |
109 | you can use wxLog::EnableLogging() method or, more usually, wxLogNull class | |
110 | which temporarily disables logging and restores it back to the original setting | |
111 | when it is destroyed. | |
112 | ||
113 | To limit logging to important messages only, you may use wxLog::SetLogLevel() | |
114 | with e.g. wxLOG_Warning value -- this will completely disable all logging | |
115 | messages with the severity less than warnings, so wxLogMessage() output won't | |
116 | be shown to the user any more. | |
117 | ||
118 | Moreover, the log level can be set separately for different log components. | |
119 | Before showing how this can be useful, let us explain what log components are: | |
120 | they are simply arbitrary strings identifying the component, or module, which | |
121 | generated the message. They are hierarchical in the sense that "foo/bar/baz" | |
122 | component is supposed to be a child of "foo". And all components are children | |
123 | of the unnamed root component. | |
124 | ||
125 | By default, all messages logged by wxWidgets originate from "wx" component or | |
126 | one of its subcomponents such as "wx/net/ftp", while the messages logged by | |
127 | your own code are assigned empty log component. To change this, you need to | |
128 | define @c wxLOG_COMPONENT to a string uniquely identifying each component, e.g. | |
129 | you could give it the value "MyProgram" by default and re-define it as | |
130 | "MyProgram/DB" in the module working with the database and "MyProgram/DB/Trans" | |
131 | in its part managing the transactions. Then you could use | |
132 | wxLog::SetComponentLevel() in the following ways: | |
133 | ||
134 | @code | |
135 | // disable all database error messages, everybody knows databases never | |
136 | // fail anyhow | |
137 | wxLog::SetComponentLevel("MyProgram/DB", wxLOG_FatalError); | |
138 | ||
139 | // but enable tracing for the transactions as somehow our changes don't | |
140 | // get committed sometimes | |
141 | wxLog::SetComponentLevel("MyProgram/DB/Trans", wxLOG_Trace); | |
142 | ||
143 | // also enable tracing messages from wxWidgets dynamic module loading | |
144 | // mechanism | |
145 | wxLog::SetComponentLevel("wx/base/module", wxLOG_Trace); | |
146 | @endcode | |
147 | ||
148 | Notice that the log level set explicitly for the transactions code overrides | |
149 | the log level of the parent component but that all other database code | |
150 | subcomponents inherit its setting by default and so won't generate any log | |
151 | messages at all. | |
152 | ||
153 | ||
154 | ||
155 | @section overview_log_targets Log Targets | |
156 | ||
157 | After having enumerated all the functions which are normally used to log the | |
158 | messages, and why would you want to use them, we now describe how all this | |
159 | works. | |
160 | ||
161 | wxWidgets has the notion of a <em>log target</em>: it is just a class deriving | |
162 | from wxLog. As such, it implements the virtual functions of the base class | |
163 | which are called when a message is logged. Only one log target is @e active at | |
164 | any moment, this is the one used by @ref group_funcmacro_log "wxLogXXX() functions". | |
165 | The normal usage of a log object (i.e. object of a class derived from wxLog) is | |
166 | to install it as the active target with a call to @e SetActiveTarget() and it | |
167 | will be used automatically by all subsequent calls to | |
168 | @ref group_funcmacro_log "wxLogXXX() functions". | |
169 | ||
170 | To create a new log target class you only need to derive it from wxLog and | |
171 | override one or several of wxLog::DoLogRecord(), wxLog::DoLogTextAtLevel() and | |
172 | wxLog::DoLogText() in it. The first one is the most flexible and allows you to | |
173 | change the formatting of the messages, dynamically filter and redirect them and | |
174 | so on -- all log messages, except for those generated by wxLogFatalError(), | |
175 | pass by this function. wxLog::DoLogTextAtLevel() should be overridden if you | |
176 | simply want to redirect the log messages somewhere else, without changing their | |
177 | formatting. Finally, it is enough to override wxLog::DoLogText() if you only | |
178 | want to redirect the log messages and the destination doesn't depend on the | |
179 | message log level. | |
180 | ||
181 | There are some predefined classes deriving from wxLog and which might be | |
182 | helpful to see how you can create a new log target class and, of course, may | |
183 | also be used without any change. There are: | |
184 | ||
185 | @li wxLogStderr: This class logs messages to a <tt>FILE *</tt>, using stderr by | |
186 | default as its name suggests. | |
187 | @li wxLogStream: This class has the same functionality as wxLogStderr, but uses | |
188 | @e ostream and cerr instead of <tt>FILE *</tt> and stderr. | |
189 | @li wxLogGui: This is the standard log target for wxWidgets applications (it is | |
190 | used by default if you don't do anything) and provides the most reasonable | |
191 | handling of all types of messages for given platform. | |
192 | @li wxLogWindow: This log target provides a "log console" which collects all | |
193 | messages generated by the application and also passes them to the previous | |
194 | active log target. The log window frame has a menu allowing user to clear | |
195 | the log, close it completely or save all messages to file. | |
196 | @li wxLogBuffer: This target collects all the logged messages in an internal | |
197 | buffer allowing to show them later to the user all at once. | |
198 | @li wxLogNull: The last log class is quite particular: it doesn't do anything. | |
199 | The objects of this class may be instantiated to (temporarily) suppress | |
200 | output of @e wxLogXXX() functions. As an example, trying to open a | |
201 | non-existing file will usually provoke an error message, but if for some | |
202 | reasons it is unwanted, just use this construction: | |
203 | @code | |
204 | wxFile file; | |
205 | ||
206 | // wxFile.Open() normally complains if file can't be opened, we don't want it | |
207 | { | |
208 | wxLogNull logNo; | |
209 | if ( !file.Open("bar") ) | |
210 | { | |
211 | // ... process error ourselves ... | |
212 | } | |
213 | } // ~wxLogNull called, old log sink restored | |
214 | ||
215 | wxLogMessage("..."); // ok | |
216 | @endcode | |
217 | ||
218 | @see @ref group_class_logging "Logging Classes" | |
219 | ||
220 | The log targets can also be combined: for example you may wish to redirect the | |
221 | messages somewhere else (for example, to a log file) but also process them as | |
222 | normally. For this the wxLogChain, wxLogInterposer, and wxLogInterposerTemp can | |
223 | be used. | |
224 | ||
225 | ||
226 | ||
227 | @section overview_log_mt Logging in Multi-Threaded Applications | |
228 | ||
229 | Starting with wxWidgets 2.9.1, logging functions can be safely called from any | |
230 | thread. Messages logged from threads other than the main one will be buffered | |
231 | until wxLog::Flush() is called in the main thread (which usually happens during | |
232 | idle time, i.e. after processing all pending events) and will be really output | |
233 | only then. Notice that the default GUI logger already only output the messages | |
234 | when it is flushed, so by default messages from the other threads will be shown | |
235 | more or less at the same moment as usual. However if you define a custom log | |
236 | target, messages may be logged out of order, e.g. messages from the main thread | |
237 | with later timestamp may appear before messages with earlier timestamp logged | |
238 | from other threads. wxLog does however guarantee that messages logged by each | |
239 | thread will appear in order in which they were logged. | |
240 | ||
241 | Also notice that wxLog::EnableLogging() and wxLogNull class which uses it only | |
242 | affect the current thread, i.e. logging messages may still be generated by the | |
243 | other threads after a call to @c EnableLogging(false). | |
244 | ||
245 | ||
246 | ||
247 | @section overview_log_customize Logging Customization | |
248 | ||
249 | To completely change the logging behaviour you may define a custom log target. | |
250 | For example, you could define a class inheriting from wxLog which shows all the | |
251 | log messages in some part of your main application window reserved for the | |
252 | message output without interrupting the user work flow with modal message | |
253 | boxes. | |
254 | ||
255 | To use your custom log target you may either call wxLog::SetActiveTarget() with | |
256 | your custom log object or create a wxAppTraits-derived class and override | |
257 | wxAppTraits::CreateLogTarget() virtual method in it and also override wxApp::CreateTraits() | |
258 | to return an instance of your custom traits object. Notice that in the latter | |
259 | case you should be prepared for logging messages early during the program | |
260 | startup and also during program shutdown so you shouldn't rely on existence of | |
261 | the main application window, for example. You can however safely assume that | |
262 | GUI is (already/still) available when your log target as used as wxWidgets | |
263 | automatically switches to using wxLogStderr if it isn't. | |
264 | ||
265 | There are several methods which may be overridden in the derived class to | |
266 | customize log messages handling: wxLog::DoLogRecord(), wxLog::DoLogTextAtLevel() | |
267 | and wxLog::DoLogText(). | |
268 | ||
269 | The last method is the simplest one: you should override it if you simply | |
270 | want to redirect the log output elsewhere, without taking into account the | |
271 | level of the message. If you do want to handle messages of different levels | |
272 | differently, then you should override wxLog::DoLogTextAtLevel(). | |
273 | ||
274 | Additionally, you can customize the way full log messages are constructed from | |
275 | the components (such as time stamp, source file information, logging thread ID | |
276 | and so on). This task is performed by wxLogFormatter class so you need to | |
277 | derive a custom class from it and override its Format() method to build the log | |
278 | messages in desired way. Notice that if you just need to modify (or suppress) | |
279 | the time stamp display, overriding FormatTime() is enough. | |
280 | ||
281 | Finally, if even more control over the output format is needed, then | |
282 | DoLogRecord() can be overridden as it allows to construct custom messages | |
283 | depending on the log level or even do completely different things depending | |
284 | on the message severity (for example, throw away all messages except | |
285 | warnings and errors, show warnings on the screen and forward the error | |
286 | messages to the user's (or programmer's) cell phone -- maybe depending on | |
287 | whether the timestamp tells us if it is day or night in the current time | |
288 | zone). | |
289 | ||
290 | The @e dialog sample illustrates this approach by defining a custom log target | |
291 | customizing the dialog used by wxLogGui for the single messages. | |
292 | ||
293 | ||
294 | @section overview_log_tracemasks Using Trace Masks | |
295 | ||
296 | Notice that the use of log trace masks is hardly necessary any longer in | |
297 | current wxWidgets version as the same effect can be achieved by using | |
298 | different log components for different log statements of any level. Please | |
299 | see @ref overview_log_enable for more information about the log components. | |
300 | ||
301 | The functions below allow some limited customization of wxLog behaviour | |
302 | without writing a new log target class (which, aside from being a matter of | |
303 | several minutes, allows you to do anything you want). | |
304 | The verbose messages are the trace messages which are not disabled in the | |
305 | release mode and are generated by wxLogVerbose(). | |
306 | They are not normally shown to the user because they present little interest, | |
307 | but may be activated, for example, in order to help the user find some program | |
308 | problem. | |
309 | ||
310 | As for the (real) trace messages, their handling depends on the currently | |
311 | enabled trace masks: if wxLog::AddTraceMask() was called for the mask of the given | |
312 | message, it will be logged, otherwise nothing happens. | |
313 | ||
314 | For example, | |
315 | @code | |
316 | wxLogTrace( wxTRACE_OleCalls, "IFoo::Bar() called" ); | |
317 | @endcode | |
318 | ||
319 | will log the message if it was preceded by: | |
320 | ||
321 | @code | |
322 | wxLog::AddTraceMask( wxTRACE_OleCalls ); | |
323 | @endcode | |
324 | ||
325 | The standard trace masks are given in wxLogTrace() documentation. | |
326 | ||
327 | */ |