fgms 0.11.8
The
FlightGear MultiPlayer Server
project
logstream.hxx
Go to the documentation of this file.
1 /**
2  * @file logstream.hxx
3  * @author Bernie Bright, 1998
4  * @brief Stream based logging mechanism.
5  *
6  */
7 
8 // Written by Bernie Bright, 1998
9 //
10 // Copyright (C) 1998 Bernie Bright - bbright@c031.aone.net.au
11 //
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Library General Public
14 // License as published by the Free Software Foundation; either
15 // version 2 of the License, or (at your option) any later version.
16 //
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // Library General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 //
26 // $Id: logstream.hxx,v 1.2 2010/02/15 08:04:17 oliver Exp $
27 
28 #ifndef _LOGSTREAM_H
29 #define _LOGSTREAM_H
30 
31 #include <simgear/compiler.h>
32 
33 #ifdef _MSC_VER
34 # include <windows.h>
35 #endif
36 
37 #ifdef SG_HAVE_STD_INCLUDES
38 # include <streambuf>
39 # include <iostream>
40 #else
41 # include <iostream.h>
42 # include <simgear/sg_traits.hxx>
43 #endif
44 
45 #include <cstdio>
47 
48 SG_USING_STD ( streambuf );
49 SG_USING_STD ( ostream );
50 SG_USING_STD ( cout );
51 SG_USING_STD ( cerr );
52 SG_USING_STD ( endl );
53 SG_USING_STD ( string );
54 
55 #ifdef __MWERKS__
56 SG_USING_STD ( iostream );
57 #endif
58 
59 //
60 // TODO:
61 //
62 // 1. Change output destination. Done.
63 // 2. Make logbuf thread safe.
64 // 3. Read environment for default debugClass and debugPriority.
65 //
66 
67 /**
68  * @brief The user can provide a function which returns a date as a string
69  */
70 typedef string ( *DATEFUNC ) ( void );
71 
72 /**
73  * @class logbuf
74  * @brief logbuf is an output-only streambuf
75  *
76  * logbuf is an output-only streambuf with the ability to disable sets of
77  * messages at runtime. Only messages with priority >= logbuf::logPriority
78  * and debugClass == logbuf::logClass are output.
79  */
80 #ifdef SG_NEED_STREAMBUF_HACK
81 class logbuf : public __streambuf
82 #else
83 class logbuf : public streambuf
84 #endif
85 {
86 public:
87 
88 #ifndef SG_HAVE_STD_INCLUDES
89  typedef char_traits<char> traits_type;
90  typedef char_traits<char>::int_type int_type;
91 #endif
92  /** @brief Constructor */
93  logbuf();
94 
95  /** @brief Destructor */
96  ~logbuf();
97 
98  /**
99  * @brief Is logging enabled?
100  * @return true or false*/
101  bool enabled()
102  {
103  return logging_enabled;
104  }
105 
106  /**
107  * @brief Set the logging level of subsequent messages.
108  * @param c debug class
109  * @param p priority
110  */
112 
113  /**
114  * @brief Set the global logging level.
115  * @param c debug class
116  * @param p priority
117  */
118  static void set_log_level ( sgDebugClass c, sgDebugPriority p );
119 
120 
121  /**
122  * @brief Set the allowed logging classes.
123  * @param c All enabled logging classes anded together.
124  */
125  static void set_log_classes ( sgDebugClass c );
126 
127  /**
128  * @brief enable logging of a single class
129  * @param c the class to be enabled
130  */
131  static void enable_log_class ( sgDebugClass c );
132 
133  /**
134  * @brief disable logging of a single class
135  * @param c the class to be disabled
136  */
137  static void disable_log_class ( sgDebugClass c );
138 
139  /**
140  * @brief Get the logging classes currently enabled.
141  * @return All enabled debug logging anded together.
142  */
143  static sgDebugClass get_log_classes ();
144 
145 
146  /**
147  * @brief Set the logging priority.
148  * @param p The priority cutoff for logging messages.
149  */
150  static void set_log_priority ( sgDebugPriority p );
151 
152 
153  /**
154  * @brief Get the current logging priority.
155  * @return The priority cutoff for logging messages.
156  */
158 
159 
160  /**
161  * @brief Set the stream buffer
162  * @param sb stream buffer
163  */
164  void set_sb ( streambuf* sb );
165 
166 #ifdef _MSC_VER
167  static void has_no_console()
168  {
169  has_console = false;
170  }
171 #endif
172 
173 protected:
174 
175  /** @brief sync/flush */
176  inline virtual int sync();
177 
178  /** @brief overflow */
179  int_type overflow ( int ch );
180  // int xsputn( const char* s, istreamsize n );
181 
182 private:
183 
184  /** @brief The streambuf used for actual output. Defaults to cerr.rdbuf(). */
185  static streambuf* sbuf;
186 
187  static bool logging_enabled; // log to file
188  static bool console_enabled; // log to console
189 #ifdef _MSC_VER
190  static bool has_console;
191 #endif
194 
195 private:
196 
197  // Not defined.
198  logbuf ( const logbuf& );
199  void operator= ( const logbuf& );
200 };
201 
202 inline int
204 {
205 #ifdef SG_HAVE_STD_INCLUDES
206  return sbuf->pubsync();
207 #else
208  return sbuf->sync();
209 #endif
210 }
211 
212 inline void
214 {
215  logging_enabled = ( (( c & logClass ) != 0) && (p >= logPriority) );
216  console_enabled = ( (( c & SG_CONSOLE ) != 0) && (p >= logPriority) );
217  if ((p == SG_ALERT) && (logPriority != SG_DISABLED))
218  logging_enabled = true; // SG_ALERT is logged regardless of logClass
219 }
220 
221 inline logbuf::int_type
223 {
224 #ifdef _MSC_VER
225  if ( logging_enabled )
226  {
227  if ( !has_console )
228  {
229  AllocConsole();
230  freopen ( "conin$", "r", stdin );
231  freopen ( "conout$", "w", stdout );
232  freopen ( "conout$", "w", stderr );
233  has_console = true;
234  }
235  return sbuf->sputc ( c );
236  }
237  else
238  {
239  return EOF == 0 ? 1: 0;
240  }
241 #else
242  if ((logging_enabled) && (console_enabled))
243  cout << (char) c;
244  return logging_enabled ? sbuf->sputc ( c ) : ( EOF == 0 ? 1: 0 );
245 #endif
246 }
247 
248 /**
249  * @struct loglevel
250  * @brief logstream manipulator for setting the log level of a message.
251  */
252 struct loglevel
253 {
255  : logClass ( c ), logPriority ( p ) {}
256 
259 };
260 
261 /**
262  * @struct logstream_base
263  * @brief A helper class
264  *
265  * Ensures a streambuf and ostream are constructed and
266  * destroyed in the correct order. The streambuf must be created before the
267  * ostream but bases are constructed before members. Thus, making this class
268  * a private base of logstream, declared to the left of ostream, we ensure the
269  * correct order of construction and destruction.
270  */
272 {
273  // logstream_base( streambuf* sb ) : lbuf(sb) {}
275 
277 };
278 
279 /**
280  * @class logstream
281  * @brief Class to manage the debug logging stream.
282  */
283 class logstream : private logstream_base, public ostream
284 {
285 public:
286  /**
287  * @brief The default is to send messages to cerr.
288  * @param out output stream
289  */
290  logstream ( ostream& out )
291  : logstream_base(), ostream ( &lbuf )
292  {
293  with_date = false;
294  userdatestr = 0;
295  lbuf.set_sb ( out.rdbuf() );
296  }
297 
298  /**
299  * @brief Set the output stream
300  * @param out output stream
301  */
302  void set_output ( ostream& out )
303  {
304  lbuf.set_sb ( out.rdbuf() );
305  }
306 
307  /**
308  * @brief Set the global log class and priority level.
309  * @param c debug class
310  * @param p priority
311  */
313 
314  /**
315  * @brief enable logging of a single class
316  * @param c the class to be enabled
317  */
318  void enable_log_class ( sgDebugClass c );
319 
320  /**
321  * @brief disable logging of a single class
322  * @param c the class to be disabled
323  */
324  void disable_log_class ( sgDebugClass c );
325 
326  /**
327  * @brief Output operator to capture the debug level and priority of a message.
328  * @param l log level
329  */
330  inline ostream& operator<< ( const loglevel& l );
331 
332  /**
333  * @brief Set a user provided function, which returns a date as a string
334  */
335  inline void setuserdatestr ( DATEFUNC udsf )
336  {
337  userdatestr=udsf;
338  };
339 
340  /**
341  * @brief Return a date as a string, standard format
342  */
343  string datestr ( void );
344 
345  /**
346  * @brief Enable output of date
347  */
348  inline void enable_with_date ( bool enable )
349  {
350  with_date = enable;
351  };
352  bool with_date;
353 private:
355 };
356 
357 inline ostream&
359 {
361  return *this;
362 }
363 
365 
366 /**
367  * @relates logstream
368  * @brief Return the one and only logstream instance.
369  *
370  * We use a function instead of a global object so we are assured that cerr
371  * has been initialised.
372  * @return current logstream
373  */
374 inline logstream&
376 {
377  if ( global_logstream == NULL )
378  {
379 #ifdef __APPLE__
380  /**
381  * There appears to be a bug in the C++ runtime in Mac OS X that
382  * will crash if certain funtions are called (in this case
383  * cerr.rdbuf()) during static initialization of a class. This
384  * print statement is hack to kick the library in the pants so it
385  * won't crash when cerr.rdbuf() is first called -DW
386  **/
387  cout << "Using Mac OS X hack for initializing C++ stdio..." << endl;
388 #endif
389  global_logstream = new logstream ( cerr );
390  }
391  return *global_logstream;
392 }
393 
394 /** \def SG_LOG(C,P,M)
395  * Log a message.
396  * @param C debug class
397  * @param P priority
398  * @param M message
399  */
400 #ifdef FG_NDEBUG
401 # define SG_LOG(C,P,M)
402 # define SG_ALERT(C,P,M)
403 #elif defined( __MWERKS__ )
404 # define SG_LOG(C,P,M) ::sglog() << ::loglevel(C,P) << M << std::endl
405 # define SG_CONSOLE(C,P,M) ::sglog() << ::loglevel((sgDebugClass) (C|SG_CONSOLE),P) << ::sglog().datestr() << M << "\r\n";
406 #else
407 #ifdef _MSC_VER
408 # define SG_CONSOLE(C,P,M) sglog() << loglevel((sgDebugClass) (C|SG_CONSOLE),P) << sglog().datestr() << M << "\r\n"; \
409  cerr << sglog().datestr() << M << "\r\n";
410 # define SG_LOG(C,P,M) SG_CONSOLE(C,P,M)
411 #else
412 # define SG_LOG(C,P,M) sglog() << loglevel(C,P) << sglog().datestr() << M << std::endl
413 # define SG_CONSOLE(C,P,M) sglog() << loglevel((sgDebugClass) (C|SG_CONSOLE),P) << sglog().datestr() << M << "\r\n";
414 #endif
415 #endif
416 
417 #endif // _LOGSTREAM_H
418 
static void set_log_priority(sgDebugPriority p)
Set the logging priority.
Definition: logstream.cxx:98
void setLogLevels(sgDebugClass c, sgDebugPriority p)
Set the global log class and priority level.
Definition: logstream.cxx:123
#define SG_CONSOLE(C, P, M)
Definition: logstream.hxx:413
static sgDebugPriority logPriority
Definition: logstream.hxx:193
A helper class.
Definition: logstream.hxx:271
SG_USING_STD(streambuf)
void operator=(const logbuf &)
logstream * global_logstream
Definition: logstream.cxx:29
static void set_log_level(sgDebugClass c, sgDebugPriority p)
Set the global logging level.
Definition: logstream.cxx:63
static void disable_log_class(sgDebugClass c)
disable logging of a single class
Definition: logstream.cxx:84
virtual int sync()
sync/flush
Definition: logstream.hxx:203
ostream & operator<<(const loglevel &l)
Output operator to capture the debug level and priority of a message.
Definition: logstream.hxx:358
logbuf is an output-only streambuf
Definition: logstream.hxx:83
DATEFUNC userdatestr
Definition: logstream.hxx:354
bool with_date
Definition: logstream.hxx:351
logstream(ostream &out)
The default is to send messages to cerr.
Definition: logstream.hxx:290
sgDebugPriority
Define the possible logging priorities (and their order).
Definition: debug_types.h:24
void set_output(ostream &out)
Set the output stream.
Definition: logstream.hxx:302
int_type overflow(int ch)
overflow
Definition: logstream.hxx:222
void disable_log_class(sgDebugClass c)
disable logging of a single class
Definition: logstream.cxx:117
static sgDebugPriority get_log_priority()
Get the current logging priority.
Definition: logstream.cxx:104
bool enabled()
Is logging enabled?
Definition: logstream.hxx:101
void setuserdatestr(DATEFUNC udsf)
Set a user provided function, which returns a date as a string.
Definition: logstream.hxx:335
sgDebugPriority logPriority
Definition: logstream.hxx:258
loglevel(sgDebugClass c, sgDebugPriority p)
Definition: logstream.hxx:254
Define the various logging classes and prioritiess.
void enable_log_class(sgDebugClass c)
enable logging of a single class
Definition: logstream.cxx:111
Class to manage the debug logging stream.
Definition: logstream.hxx:283
logbuf()
Constructor.
Definition: logstream.cxx:40
logstream & sglog()
Return the one and only logstream instance.
Definition: logstream.hxx:375
sgDebugClass logClass
Definition: logstream.hxx:257
void set_log_state(sgDebugClass c, sgDebugPriority p)
Set the logging level of subsequent messages.
Definition: logstream.hxx:213
static void enable_log_class(sgDebugClass c)
enable logging of a single class
Definition: logstream.cxx:76
char_traits< char >::int_type int_type
Definition: logstream.hxx:90
Very possible impending problem.
Definition: debug_types.h:38
static sgDebugClass logClass
Definition: logstream.hxx:192
sgDebugClass
Define the possible classes/categories of logging messages.
Definition: debug_types.h:8
void enable_with_date(bool enable)
Enable output of date.
Definition: logstream.hxx:348
static void set_log_classes(sgDebugClass c)
Set the allowed logging classes.
Definition: logstream.cxx:70
static bool console_enabled
Definition: logstream.hxx:188
void set_sb(streambuf *sb)
Set the stream buffer.
Definition: logstream.cxx:53
~logbuf()
Destructor.
Definition: logstream.cxx:44
string datestr(void)
Return a date as a string, standard format.
Definition: logstream.cxx:129
static sgDebugClass get_log_classes()
Get the logging classes currently enabled.
Definition: logstream.cxx:92
static streambuf * sbuf
The streambuf used for actual output. Defaults to cerr.rdbuf().
Definition: logstream.hxx:185
char_traits< char > traits_type
Definition: logstream.hxx:89
static bool logging_enabled
Definition: logstream.hxx:187
string(* DATEFUNC)(void)
The user can provide a function which returns a date as a string.
Definition: logstream.hxx:70
logstream manipulator for setting the log level of a message.
Definition: logstream.hxx:252