]> git.mxchange.org Git - simgear.git/blob - simgear/debug/logstream.hxx
f28ca6103c2342773b5ddb96d22df10a7e9ffc53
[simgear.git] / simgear / debug / logstream.hxx
1 /** \file logstream.hxx
2  * Stream based logging mechanism.
3  */
4
5 // Written by Bernie Bright, 1998
6 //
7 // Copyright (C) 1998  Bernie Bright - bbright@c031.aone.net.au
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Library General Public
11 // License as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // Library General Public License for more details.
18 //
19 // You should have received a copy of the GNU Library General Public
20 // License along with this library; if not, write to the
21 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 // Boston, MA  02111-1307, USA.
23 //
24 // $Id$
25
26 #ifndef _LOGSTREAM_H
27 #define _LOGSTREAM_H
28
29 #include <simgear/compiler.h>
30
31 // At least Irix needs this
32 #ifdef SG_HAVE_NATIVE_SGI_COMPILERS
33 #include <char_traits.h>
34 #endif
35
36 #ifdef SG_HAVE_STD_INCLUDES
37 # include <streambuf>
38 # include <iostream>
39 #else
40 # include <iostream.h>
41 # include <simgear/sg_traits.hxx>
42 #endif
43
44 #include <simgear/debug/debug_types.h>
45
46 #ifndef SG_HAVE_NATIVE_SGI_COMPILERS
47 SG_USING_STD(streambuf);
48 SG_USING_STD(ostream);
49 SG_USING_STD(cout);
50 SG_USING_STD(cerr);
51 SG_USING_STD(endl);
52 #else
53 SG_USING_STD(char_traits);
54 #endif
55
56 #ifdef __MWERKS__
57 SG_USING_STD(iostream);
58 #endif
59
60 //
61 // TODO:
62 //
63 // 1. Change output destination. Done.
64 // 2. Make logbuf thread safe.
65 // 3. Read environment for default debugClass and debugPriority.
66 //
67
68 /**
69  * logbuf is an output-only streambuf with the ability to disable sets of
70  * messages at runtime. Only messages with priority >= logbuf::logPriority
71  * and debugClass == logbuf::logClass are output.
72  */
73 class logbuf : public streambuf
74 {
75 public:
76
77 #ifndef SG_HAVE_STD_INCLUDES
78     typedef char_traits<char>           traits_type;
79     typedef char_traits<char>::int_type int_type;
80     // typedef char_traits<char>::pos_type pos_type;
81     // typedef char_traits<char>::off_type off_type;
82 #endif
83     // logbuf( streambuf* sb ) : sbuf(sb) {}
84     /** Constructor */
85     logbuf();
86
87     /** Destructor */
88     ~logbuf();
89
90     /**
91      * Is logging enabled?
92      * @return true or false*/
93     bool enabled() { return logging_enabled; }
94
95     /**
96      * Set the logging level of subsequent messages.
97      * @param c debug class
98      * @param p priority
99      */
100     void set_log_state( sgDebugClass c, sgDebugPriority p );
101
102     /**
103      * Set the global logging level.
104      * @param c debug class
105      * @param p priority
106      */
107     static void set_log_level( sgDebugClass c, sgDebugPriority p );
108
109
110     /**
111      * Set the allowed logging classes.
112      * @param c All enabled logging classes anded together.
113      */
114     static void set_log_classes (sgDebugClass c);
115
116
117     /**
118      * Get the logging classes currently enabled.
119      * @return All enabled debug logging anded together.
120      */
121     static sgDebugClass get_log_classes ();
122
123
124     /**
125      * Set the logging priority.
126      * @param c The priority cutoff for logging messages.
127      */
128     static void set_log_priority (sgDebugPriority p);
129
130
131     /**
132      * Get the current logging priority.
133      * @return The priority cutoff for logging messages.
134      */
135     static sgDebugPriority get_log_priority ();
136
137
138     /**
139      * Set the stream buffer
140      * @param sb stream buffer
141      */
142     void set_sb( streambuf* sb );
143
144 protected:
145
146     /** sync/flush */
147     inline virtual int sync();
148
149     /** overflow */
150     int_type overflow( int ch );
151     // int xsputn( const char* s, istreamsize n );
152
153 private:
154
155     // The streambuf used for actual output. Defaults to cerr.rdbuf().
156     static streambuf* sbuf;
157
158     static bool logging_enabled;
159     static sgDebugClass logClass;
160     static sgDebugPriority logPriority;
161
162 private:
163
164     // Not defined.
165     logbuf( const logbuf& );
166     void operator= ( const logbuf& );
167 };
168
169 inline int
170 logbuf::sync()
171 {
172 #ifdef SG_HAVE_STD_INCLUDES
173         return sbuf->pubsync();
174 #else
175         return sbuf->sync();
176 #endif
177 }
178
179 inline void
180 logbuf::set_log_state( sgDebugClass c, sgDebugPriority p )
181 {
182     logging_enabled = ((c & logClass) != 0 && p >= logPriority);
183 }
184
185 inline logbuf::int_type
186 logbuf::overflow( int c )
187 {
188     return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0);
189 }
190
191 /**
192  * logstream manipulator for setting the log level of a message.
193  */
194 struct loglevel
195 {
196     loglevel( sgDebugClass c, sgDebugPriority p )
197         : logClass(c), logPriority(p) {}
198
199     sgDebugClass logClass;
200     sgDebugPriority logPriority;
201 };
202
203 /**
204  * A helper class that ensures a streambuf and ostream are constructed and
205  * destroyed in the correct order.  The streambuf must be created before the
206  * ostream but bases are constructed before members.  Thus, making this class
207  * a private base of logstream, declared to the left of ostream, we ensure the
208  * correct order of construction and destruction.
209  */
210 struct logstream_base
211 {
212     // logstream_base( streambuf* sb ) : lbuf(sb) {}
213     logstream_base() {}
214
215     logbuf lbuf;
216 };
217
218 /**
219  * Class to manage the debug logging stream.
220  */
221 class logstream : private logstream_base, public ostream
222 {
223 public:
224     /**
225      * The default is to send messages to cerr.
226      * @param out output stream
227      */
228     logstream( ostream& out )
229         // : logstream_base(out.rdbuf()),
230         : logstream_base(),
231           ostream(&lbuf) { lbuf.set_sb(out.rdbuf());}
232
233     /**
234      * Set the output stream
235      * @param out output stream
236      */
237     void set_output( ostream& out ) { lbuf.set_sb( out.rdbuf() ); }
238
239     /**
240      * Set the global log class and priority level.
241      * @param c debug class
242      * @param p priority
243      */
244     void setLogLevels( sgDebugClass c, sgDebugPriority p );
245
246     /**
247      * Output operator to capture the debug level and priority of a message.
248      * @param l log level
249      */
250     inline ostream& operator<< ( const loglevel& l );
251 };
252
253 inline ostream&
254 logstream::operator<< ( const loglevel& l )
255 {
256     lbuf.set_log_state( l.logClass, l.logPriority );
257     return *this;
258 }
259
260 extern logstream *global_logstream;
261
262 /**
263  * \relates logstream
264  * Return the one and only logstream instance.
265  * We use a function instead of a global object so we are assured that cerr
266  * has been initialised.
267  * @return current logstream
268  */
269 inline logstream&
270 sglog()
271 {
272   if (global_logstream == NULL) {
273
274 #ifdef __APPLE__
275     /**
276      * There appears to be a bug in the C++ runtime in Mac OS X that
277      * will crash if certain funtions are called (in this case
278      * cerr.rdbuf()) during static initialization of a class. This
279      * print statement is hack to kick the library in the pants so it
280      * won't crash when cerr.rdbuf() is first called -DW 
281      **/
282     cout << "Using Mac OS X hack for initializing C++ stdio..." << endl;
283 #endif    
284     global_logstream = new logstream (cerr);
285   }
286     
287   return *global_logstream;
288 }
289
290
291 /** \def SG_LOG(C,P,M)
292  * Log a message.
293  * @param C debug class
294  * @param P priority
295  * @param M message
296  */
297 #ifdef FG_NDEBUG
298 # define SG_LOG(C,P,M)
299 #elif defined( __MWERKS__ )
300 # define SG_LOG(C,P,M) ::sglog() << ::loglevel(C,P) << M << std::endl
301 #else
302 # define SG_LOG(C,P,M) sglog() << loglevel(C,P) << M << endl
303 #endif
304
305
306 #endif // _LOGSTREAM_H
307