]> git.mxchange.org Git - simgear.git/blob - simgear/debug/logstream.hxx
ea35ee956c66d935ba575a23c8feab1feb35f060
[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(cerr);
50 SG_USING_STD(endl);
51 #else
52 SG_USING_STD(char_traits);
53 #endif
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  * logbuf is an output-only streambuf with the ability to disable sets of
69  * messages at runtime. Only messages with priority >= logbuf::logPriority
70  * and debugClass == logbuf::logClass are output.
71  */
72 class logbuf : public streambuf
73 {
74 public:
75
76 #ifndef SG_HAVE_STD_INCLUDES
77     typedef char_traits<char>           traits_type;
78     typedef char_traits<char>::int_type int_type;
79     // typedef char_traits<char>::pos_type pos_type;
80     // typedef char_traits<char>::off_type off_type;
81 #endif
82     // logbuf( streambuf* sb ) : sbuf(sb) {}
83     /** Constructor */
84     logbuf();
85
86     /** Destructor */
87     ~logbuf();
88
89     /**
90      * Is logging enabled?
91      * @return true or false*/
92     bool enabled() { return logging_enabled; }
93
94     /**
95      * Set the logging level of subsequent messages.
96      * @param c debug class
97      * @param p priority
98      */
99     void set_log_state( sgDebugClass c, sgDebugPriority p );
100
101     /**
102      * Set the global logging level.
103      * @param c debug class
104      * @param p priority
105      */
106     static void set_log_level( sgDebugClass c, sgDebugPriority p );
107
108
109     /**
110      * Set the allowed logging classes.
111      * @param c All enabled logging classes anded together.
112      */
113     static void set_log_classes (sgDebugClass c);
114
115
116     /**
117      * Get the logging classes currently enabled.
118      * @return All enabled debug logging anded together.
119      */
120     static sgDebugClass get_log_classes ();
121
122
123     /**
124      * Set the logging priority.
125      * @param c The priority cutoff for logging messages.
126      */
127     static void set_log_priority (sgDebugPriority p);
128
129
130     /**
131      * Get the current logging priority.
132      * @return The priority cutoff for logging messages.
133      */
134     static sgDebugPriority get_log_priority ();
135
136
137     /**
138      * Set the stream buffer
139      * @param sb stream buffer
140      */
141     void set_sb( streambuf* sb );
142
143 protected:
144
145     /** sync/flush */
146     inline virtual int sync();
147
148     /** overflow */
149     int_type overflow( int ch );
150     // int xsputn( const char* s, istreamsize n );
151
152 private:
153
154     // The streambuf used for actual output. Defaults to cerr.rdbuf().
155     static streambuf* sbuf;
156
157     static bool logging_enabled;
158     static sgDebugClass logClass;
159     static sgDebugPriority logPriority;
160
161 private:
162
163     // Not defined.
164     logbuf( const logbuf& );
165     void operator= ( const logbuf& );
166 };
167
168 inline int
169 logbuf::sync()
170 {
171 #ifdef SG_HAVE_STD_INCLUDES
172         return sbuf->pubsync();
173 #else
174         return sbuf->sync();
175 #endif
176 }
177
178 inline void
179 logbuf::set_log_state( sgDebugClass c, sgDebugPriority p )
180 {
181     logging_enabled = ((c & logClass) != 0 && p >= logPriority);
182 }
183
184 inline logbuf::int_type
185 logbuf::overflow( int c )
186 {
187     return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0);
188 }
189
190 /**
191  * logstream manipulator for setting the log level of a message.
192  */
193 struct loglevel
194 {
195     loglevel( sgDebugClass c, sgDebugPriority p )
196         : logClass(c), logPriority(p) {}
197
198     sgDebugClass logClass;
199     sgDebugPriority logPriority;
200 };
201
202 /**
203  * A helper class that ensures a streambuf and ostream are constructed and
204  * destroyed in the correct order.  The streambuf must be created before the
205  * ostream but bases are constructed before members.  Thus, making this class
206  * a private base of logstream, declared to the left of ostream, we ensure the
207  * correct order of construction and destruction.
208  */
209 struct logstream_base
210 {
211     // logstream_base( streambuf* sb ) : lbuf(sb) {}
212     logstream_base() {}
213
214     logbuf lbuf;
215 };
216
217 /**
218  * Class to manage the debug logging stream.
219  */
220 class logstream : private logstream_base, public ostream
221 {
222 public:
223     /**
224      * The default is to send messages to cerr.
225      * @param out output stream
226      */
227     logstream( ostream& out )
228         // : logstream_base(out.rdbuf()),
229         : logstream_base(),
230           ostream(&lbuf) { lbuf.set_sb(out.rdbuf());}
231
232     /**
233      * Set the output stream
234      * @param out output stream
235      */
236     void set_output( ostream& out ) { lbuf.set_sb( out.rdbuf() ); }
237
238     /**
239      * Set the global log class and priority level.
240      * @param c debug class
241      * @param p priority
242      */
243     void setLogLevels( sgDebugClass c, sgDebugPriority p );
244
245     /**
246      * Output operator to capture the debug level and priority of a message.
247      * @param l log level
248      */
249     inline ostream& operator<< ( const loglevel& l );
250 };
251
252 inline ostream&
253 logstream::operator<< ( const loglevel& l )
254 {
255     lbuf.set_log_state( l.logClass, l.logPriority );
256     return *this;
257 }
258
259 extern logstream *global_logstream;
260
261 /**
262  * \relates logstream
263  * Return the one and only logstream instance.
264  * We use a function instead of a global object so we are assured that cerr
265  * has been initialised.
266  * @return current logstream
267  */
268 inline logstream&
269 sglog()
270 {
271   if (global_logstream == NULL) {
272
273 #ifdef __APPLE__
274     /**
275      * There appears to be a bug in the C++ runtime in Mac OS X that
276      * will crash if certain funtions are called (in this case
277      * cerr.rdbuf()) during static initialization of a class. This
278      * print statement is hack to kick the library in the pants so it
279      * won't crash when cerr.rdbuf() is first called -DW 
280      **/
281     cout << "Using Mac OS X hack for initializing C++ stdio..." << endl;
282 #endif    
283     global_logstream = new logstream (cerr);
284   }
285     
286   return *global_logstream;
287 }
288
289
290 /** \def SG_LOG(C,P,M)
291  * Log a message.
292  * @param C debug class
293  * @param P priority
294  * @param M message
295  */
296 #ifdef FG_NDEBUG
297 # define SG_LOG(C,P,M)
298 #elif defined( __MWERKS__ )
299 # define SG_LOG(C,P,M) ::sglog() << ::loglevel(C,P) << M << std::endl
300 #else
301 # define SG_LOG(C,P,M) sglog() << loglevel(C,P) << M << endl
302 #endif
303
304
305 #endif // _LOGSTREAM_H
306