]> git.mxchange.org Git - simgear.git/blob - simgear/debug/logstream.hxx
e2977bf6d412863efce066f4e65223ac35add37e
[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 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif
32
33 #include <simgear/compiler.h>
34
35 // At least Irix needs this
36 #ifdef SG_HAVE_NATIVE_SGI_COMPILERS
37 #include <char_traits.h>
38 #endif
39
40 #ifdef SG_HAVE_STD_INCLUDES
41 # include <streambuf>
42 # include <iostream>
43 #else
44 # include <iostream.h>
45 # include <simgear/sg_traits.hxx>
46 #endif
47
48 #include <simgear/debug/debug_types.h>
49
50 #ifndef SG_HAVE_NATIVE_SGI_COMPILERS
51 SG_USING_STD(streambuf);
52 SG_USING_STD(ostream);
53 SG_USING_STD(cerr);
54 SG_USING_STD(endl);
55 #else
56 SG_USING_STD(char_traits);
57 #endif
58
59 #ifdef __MWERKS__
60 SG_USING_STD(iostream);
61 #endif
62
63 //
64 // TODO:
65 //
66 // 1. Change output destination. Done.
67 // 2. Make logbuf thread safe.
68 // 3. Read environment for default debugClass and debugPriority.
69 //
70
71 /**
72  * logbuf is an output-only streambuf with the ability to disable sets of
73  * messages at runtime. Only messages with priority >= logbuf::logPriority
74  * and debugClass == logbuf::logClass are output.
75  */
76 class logbuf : public streambuf
77 {
78 public:
79
80 #ifndef SG_HAVE_STD_INCLUDES
81     typedef char_traits<char>           traits_type;
82     typedef char_traits<char>::int_type int_type;
83     // typedef char_traits<char>::pos_type pos_type;
84     // typedef char_traits<char>::off_type off_type;
85 #endif
86     // logbuf( streambuf* sb ) : sbuf(sb) {}
87     /** Constructor */
88     logbuf();
89     /** Destructor */
90     ~logbuf();
91
92     /** Is logging enabled? */
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      * Set the stream buffer
111      * @param sb stream buffer
112      */
113     void set_sb( streambuf* sb );
114
115 protected:
116
117     /** sync/flush */
118     inline virtual int sync();
119
120     /** overflow */
121     int_type overflow( int ch );
122     // int xsputn( const char* s, istreamsize n );
123
124 private:
125
126     // The streambuf used for actual output. Defaults to cerr.rdbuf().
127     static streambuf* sbuf;
128
129     static bool logging_enabled;
130     static sgDebugClass logClass;
131     static sgDebugPriority logPriority;
132
133 private:
134
135     // Not defined.
136     logbuf( const logbuf& );
137     void operator= ( const logbuf& );
138 };
139
140 inline int
141 logbuf::sync()
142 {
143 #ifdef SG_HAVE_STD_INCLUDES
144         return sbuf->pubsync();
145 #else
146         return sbuf->sync();
147 #endif
148 }
149
150 inline void
151 logbuf::set_log_state( sgDebugClass c, sgDebugPriority p )
152 {
153     logging_enabled = ((c & logClass) != 0 && p >= logPriority);
154 }
155
156 inline logbuf::int_type
157 logbuf::overflow( int c )
158 {
159     return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0);
160 }
161
162 /**
163  * logstream manipulator for setting the log level of a message.
164  */
165 struct loglevel
166 {
167     loglevel( sgDebugClass c, sgDebugPriority p )
168         : logClass(c), logPriority(p) {}
169
170     sgDebugClass logClass;
171     sgDebugPriority logPriority;
172 };
173
174 /**
175  * A helper class that ensures a streambuf and ostream are constructed and
176  * destroyed in the correct order.  The streambuf must be created before the
177  * ostream but bases are constructed before members.  Thus, making this class
178  * a private base of logstream, declared to the left of ostream, we ensure the
179  * correct order of construction and destruction.
180  */
181 struct logstream_base
182 {
183     // logstream_base( streambuf* sb ) : lbuf(sb) {}
184     logstream_base() {}
185
186     logbuf lbuf;
187 };
188
189 /**
190  * Class to manage the debug logging stream.
191  */
192 class logstream : private logstream_base, public ostream
193 {
194 public:
195     /**
196      * The default is to send messages to cerr.
197      * @param out output stream
198      */
199     logstream( ostream& out )
200         // : logstream_base(out.rdbuf()),
201         : logstream_base(),
202           ostream(&lbuf) { lbuf.set_sb(out.rdbuf());}
203
204     /**
205      * Set the output stream
206      * @param out output stream
207      */
208     void set_output( ostream& out ) { lbuf.set_sb( out.rdbuf() ); }
209
210     /**
211      * Set the global log class and priority level.
212      * @param c debug class
213      * @param p priority
214      */
215     void setLogLevels( sgDebugClass c, sgDebugPriority p );
216
217     /**
218      * Output operator to capture the debug level and priority of a message.
219      * @param l log level
220      */
221     inline ostream& operator<< ( const loglevel& l );
222 };
223
224 inline ostream&
225 logstream::operator<< ( const loglevel& l )
226 {
227     lbuf.set_log_state( l.logClass, l.logPriority );
228     return *this;
229 }
230
231
232 /**
233  * Return the one and only logstream instance.
234  * We use a function instead of a global object so we are assured that cerr
235  * has been initialised.
236  */
237 inline logstream&
238 sglog()
239 {
240     static logstream logstrm( cerr );
241     return logstrm;
242 }
243
244
245 /** \def SG_LOG(C,P,M)
246  * Log a message.
247  * @param C debug class
248  * @param P priority
249  * @param M message
250  */
251 #ifdef FG_NDEBUG
252 # define SG_LOG(C,P,M)
253 #elif defined( __MWERKS__ )
254 # define SG_LOG(C,P,M) ::sglog() << ::loglevel(C,P) << M << std::endl
255 #else
256 # define SG_LOG(C,P,M) sglog() << loglevel(C,P) << M << endl
257 #endif
258
259
260 #endif // _LOGSTREAM_H
261