]> git.mxchange.org Git - simgear.git/blob - simgear/debug/logstream.hxx
Introduce some more logging classes.
[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 General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23 // $Id$
24
25 #ifndef _LOGSTREAM_H
26 #define _LOGSTREAM_H
27
28 #include <simgear/compiler.h>
29
30 #ifdef _WIN32
31 #  include <windows.h>
32 #endif
33
34 #include <streambuf>
35 #include <ostream>
36 #include <cstdio>
37
38 #include <simgear/debug/debug_types.h>
39
40 using std::streambuf;
41 using std::ostream;
42
43 //
44 // TODO:
45 //
46 // 1. Change output destination. Done.
47 // 2. Make logbuf thread safe.
48 // 3. Read environment for default debugClass and debugPriority.
49 //
50
51 /**
52  * logbuf is an output-only streambuf with the ability to disable sets of
53  * messages at runtime. Only messages with priority >= logbuf::logPriority
54  * and debugClass == logbuf::logClass are output.
55  */
56 #ifdef SG_NEED_STREAMBUF_HACK
57 class logbuf : public __streambuf
58 #else
59 class logbuf : public std::streambuf
60 #endif
61 {
62 public:
63     // logbuf( streambuf* sb ) : sbuf(sb) {}
64     /** Constructor */
65     logbuf();
66
67     /** Destructor */
68     ~logbuf();
69
70     /**
71      * Is logging enabled?
72      * @return true or false*/
73     bool enabled() { return logging_enabled; }
74
75     /**
76      * Set the logging level of subsequent messages.
77      * @param c debug class
78      * @param p priority
79      */
80     void set_log_state( sgDebugClass c, sgDebugPriority p );
81
82     bool would_log( sgDebugClass c, sgDebugPriority p ) const;
83
84     /**
85      * Set the global logging level.
86      * @param c debug class
87      * @param p priority
88      */
89     static void set_log_level( sgDebugClass c, sgDebugPriority p );
90
91
92     /**
93      * Set the allowed logging classes.
94      * @param c All enabled logging classes anded together.
95      */
96     static void set_log_classes (sgDebugClass c);
97
98
99     /**
100      * Get the logging classes currently enabled.
101      * @return All enabled debug logging anded together.
102      */
103     static sgDebugClass get_log_classes ();
104
105
106     /**
107      * Set the logging priority.
108      * @param c The priority cutoff for logging messages.
109      */
110     static void set_log_priority (sgDebugPriority p);
111
112
113     /**
114      * Get the current logging priority.
115      * @return The priority cutoff for logging messages.
116      */
117     static sgDebugPriority get_log_priority ();
118
119
120     /**
121      * Set the stream buffer
122      * @param sb stream buffer
123      */
124     void set_sb( std::streambuf* sb );
125
126 #ifdef _WIN32
127     static void has_no_console() { has_console = false; }
128 #endif
129
130 protected:
131
132     /** sync/flush */
133     inline virtual int sync();
134
135     /** overflow */
136     int_type overflow( int ch );
137     // int xsputn( const char* s, istreamsize n );
138
139 private:
140
141     // The streambuf used for actual output. Defaults to cerr.rdbuf().
142     static std::streambuf* sbuf;
143
144     static bool logging_enabled;
145 #ifdef _WIN32
146     static bool has_console;
147 #endif
148     static sgDebugClass logClass;
149     static sgDebugPriority logPriority;
150
151 private:
152
153     // Not defined.
154     logbuf( const logbuf& );
155     void operator= ( const logbuf& );
156 };
157
158 inline int
159 logbuf::sync()
160 {
161         return sbuf->pubsync();
162 }
163
164 inline void
165 logbuf::set_log_state( sgDebugClass c, sgDebugPriority p )
166 {
167     logging_enabled = ((c & logClass) != 0 && p >= logPriority);
168 }
169
170 inline bool
171 logbuf::would_log( sgDebugClass c, sgDebugPriority p ) const
172 {
173     return ((c & logClass) != 0 && p >= logPriority);
174 }
175
176 inline logbuf::int_type
177 logbuf::overflow( int c )
178 {
179 #ifdef _WIN32
180     if ( logging_enabled ) {
181         if ( !has_console ) {
182             AllocConsole();
183             freopen("conin$", "r", stdin);
184             freopen("conout$", "w", stdout);
185             freopen("conout$", "w", stderr);
186             has_console = true;
187         }
188         return sbuf->sputc(c);
189     }
190     else
191         return EOF == 0 ? 1: 0;
192 #else
193     return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0);
194 #endif
195 }
196
197 /**
198  * logstream manipulator for setting the log level of a message.
199  */
200 struct loglevel
201 {
202     loglevel( sgDebugClass c, sgDebugPriority p )
203         : logClass(c), logPriority(p) {}
204
205     sgDebugClass logClass;
206     sgDebugPriority logPriority;
207 };
208
209 /**
210  * A helper class that ensures a streambuf and ostream are constructed and
211  * destroyed in the correct order.  The streambuf must be created before the
212  * ostream but bases are constructed before members.  Thus, making this class
213  * a private base of logstream, declared to the left of ostream, we ensure the
214  * correct order of construction and destruction.
215  */
216 struct logstream_base
217 {
218     // logstream_base( streambuf* sb ) : lbuf(sb) {}
219     logstream_base() {}
220
221     logbuf lbuf;
222 };
223
224 /**
225  * Class to manage the debug logging stream.
226  */
227 class logstream : private logstream_base, public std::ostream
228 {
229 public:
230     /**
231      * The default is to send messages to cerr.
232      * @param out output stream
233      */
234     logstream( std::ostream& out )
235         // : logstream_base(out.rdbuf()),
236         : logstream_base(),
237           std::ostream(&lbuf) { lbuf.set_sb(out.rdbuf());}
238
239     /**
240      * Set the output stream
241      * @param out output stream
242      */
243     void set_output( std::ostream& out ) { lbuf.set_sb( out.rdbuf() ); }
244
245     /**
246      * Set the global log class and priority level.
247      * @param c debug class
248      * @param p priority
249      */
250     void setLogLevels( sgDebugClass c, sgDebugPriority p );
251
252     bool would_log(  sgDebugClass c, sgDebugPriority p ) const
253     {
254         return lbuf.would_log( c, p );
255     };
256
257     /**
258      * Output operator to capture the debug level and priority of a message.
259      * @param l log level
260      */
261     inline std::ostream& operator<< ( const loglevel& l );
262     friend logstream& sglog();
263     static logstream *initGlobalLogstream();
264 protected:
265     static logstream *global_logstream;
266 };
267
268 inline std::ostream&
269 logstream::operator<< ( const loglevel& l )
270 {
271     lbuf.set_log_state( l.logClass, l.logPriority );
272     return *this;
273 }
274
275 /**
276  * \relates logstream
277  * Return the one and only logstream instance.
278  * We use a function instead of a global object so we are assured that cerr
279  * has been initialised.
280  * @return current logstream
281  */
282 inline logstream&
283 sglog()
284 {
285     return *logstream::initGlobalLogstream();
286 }
287
288
289 /** \def SG_LOG(C,P,M)
290  * Log a message.
291  * @param C debug class
292  * @param P priority
293  * @param M message
294  */
295 #ifdef FG_NDEBUG
296 # define SG_LOG(C,P,M)
297 #else
298 # define SG_LOG(C,P,M) do {                     \
299         logstream& __tmplogstreamref(sglog());                      \
300         if(__tmplogstreamref.would_log(C,P)) {                      \
301         __tmplogstreamref << loglevel(C,P) << M << std::endl; } \
302         } while(0)
303 #endif
304
305 #define SG_ORIGIN __FILE__ ":" SG_STRINGIZE(__LINE__)
306
307 #endif // _LOGSTREAM_H
308