1 // Created by Lars Gullik Bjønnes
2 // Copyright 1999 Lars Gullik Bjønnes (larsbj@lyx.org)
3 // Released into the public domain.
5 // Primarily developed for use in the LyX Project http://www.lyx.org/
6 // but should be adaptable to any project.
8 //#define TEST_DEBUGSTREAM
12 //#include "DebugStream.h"
15 // Since the current C++ lib in egcs does not have a standard implementation
16 // of basic_streambuf and basic_filebuf we don't have to include this
18 //#define MODERN_STL_STREAMS
19 #ifdef MODERN_STL_STREAMS
25 using std::streamsize;
30 ostream & operator<<(ostream & o, Debug::type t)
35 /** This is a streambuffer that never prints out anything, at least
36 that is the intention. You can call it a no-op streambuffer, and
37 the ostream that uses it will be a no-op stream.
39 class nullbuf : public streambuf {
41 #ifndef MODERN_STL_STREAMS
42 typedef char char_type;
45 virtual int sync() { return 0; }
48 virtual streamsize xsputn(char_type const *, streamsize n) {
49 // fakes a purge of the buffer by returning n
52 #ifdef MODERN_STL_STREAMS
54 virtual int_type overflow(int_type c = traits_type::eof()) {
55 // fakes success by returning c
56 return c == traits_type::eof() ? ' ' : c;
60 virtual int_type overflow(int_type c = EOF) {
61 // fakes success by returning c
62 return c == EOF ? ' ' : c;
67 /** A streambuf that sends the output to two different streambufs. These
68 can be any kind of streambufs.
70 class teebuf : public streambuf {
73 teebuf(streambuf * b1, streambuf * b2)
74 : streambuf(), sb1(b1), sb2(b2) {}
76 #ifdef MODERN_STL_STREAMS
80 return sb1->pubsync();
83 virtual streamsize xsputn(char_type const * p, streamsize n) {
85 return sb1->sputn(p, n);
88 virtual int_type overflow(int_type c = traits_type::eof()) {
93 typedef char char_type;
101 virtual streamsize xsputn(char_type const * p, streamsize n) {
103 return sb1->xsputn(p, n);
106 virtual int_type overflow(int_type c = EOF) {
108 return sb1->overflow(c);
119 class debugbuf : public streambuf {
122 debugbuf(streambuf * b)
123 : streambuf(), sb(b) {}
125 #ifdef MODERN_STL_STREAMS
128 return sb->pubsync();
131 virtual streamsize xsputn(char_type const * p, streamsize n) {
132 return sb->sputn(p, n);
135 virtual int_type overflow(int_type c = traits_type::eof()) {
139 typedef char char_type;
140 typedef int int_type;
146 virtual streamsize xsputn(char_type const * p, streamsize n) {
147 return sb->xsputn(p, n);
150 virtual int_type overflow(int_type c = EOF) {
151 return sb->overflow(c);
160 /// So that public parts of DebugStream does not need to know about filebuf
161 struct DebugStream::debugstream_internal {
162 /// Used when logging to file.
167 /// Constructor, sets the debug level to t.
168 DebugStream::DebugStream(Debug::type t)
169 : ostream(new debugbuf(cerr.rdbuf())),
170 dt(t), nullstream(new nullbuf), internal(0) {}
173 /// Constructor, sets the log file to f, and the debug level to t.
174 DebugStream::DebugStream(char const * f, Debug::type t)
175 : ostream(new debugbuf(cerr.rdbuf())),
176 dt(t), nullstream(new nullbuf),
177 internal(new debugstream_internal)
179 internal->fbuf.open(f, ios::out|ios::app);
180 delete rdbuf(new teebuf(cerr.rdbuf(),
185 DebugStream::~DebugStream()
187 delete nullstream.rdbuf(0); // Without this we leak
188 delete rdbuf(0); // Without this we leak
193 /// Sets the debugstreams' logfile to f.
194 void DebugStream::logFile(char const * f)
197 internal->fbuf.close();
199 internal = new debugstream_internal;
201 internal->fbuf.open(f, ios::out|ios::app);
202 delete rdbuf(new teebuf(cerr.rdbuf(),
207 #ifdef TEST_DEBUGSTREAM
209 // Example debug stream
210 DebugStream debugstream;
212 int main(int, char **)
215 I have been running some tests on this to see how much overhead
216 this kind of permanent debug code has. My conclusion is: not
217 much. In all, but the most time critical code, this will have
218 close to no impact at all.
220 In the tests that I have run the use of
221 if (debugstream.debugging(DebugStream::INFO))
222 debugstream << "some debug\n";
223 has close to no overhead when the debug level is not
227 debugstream.debug(DebugStream::INFO) << "some debug\n";
228 is also very small when the debug level is not
229 DebugStream::INFO. However the overhead for this will increase
230 if complex debugging information is output.
232 The overhead when the debug level is DebugStream::INFO can be
233 significant, but since we then are running in debug mode it is
236 Why should we use this instead of the class Error that we already
237 have? First of all it uses C++ iostream and constructs, secondly
238 it will be a lot easier to output the debug info that we need
239 without a lot of manual conversions, thirdly we can now use
240 iomanipulators and the complete iostream formatting functions.
241 pluss it will work for all types that have a operator<<
242 defined, and can be used in functors that take a ostream & as
243 parameter. And there should be less need for temporary objects.
244 And one nice bonus is that we get a log file almost for
247 Some of the names are of course open to modifications. I will try
248 to use the names we already use in LyX.
250 // Just a few simple debugs to show how it can work.
251 debugstream << "Debug level set to Debug::NONE\n";
252 if (debugstream.debugging()) {
253 debugstream << "Something must be debugged\n";
255 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
256 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
257 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
258 debugstream.level(Debug::value("INFO"));
259 debugstream << "Setting debug level to Debug::INFO\n";
260 if (debugstream.debugging()) {
261 debugstream << "Something must be debugged\n";
263 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
264 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
265 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
266 debugstream.addLevel(Debug::type(Debug::CRIT |
268 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
269 debugstream[Debug::WARN] << "more debug(WARN)\n";
270 debugstream[Debug::INFO] << "even more debug(INFO)\n";
271 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
272 debugstream.delLevel(Debug::INFO);
273 debugstream << "Removing Debug::INFO\n";
274 debugstream[Debug::WARN] << "more debug(WARN)\n";
275 debugstream[Debug::INFO] << "even more debug(INFO)\n";
276 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
277 debugstream.logFile("logfile");
278 debugstream << "Setting logfile to \"logfile\"\n";
279 debugstream << "Value: " << 123 << " " << "12\n";
282 // note: the (void*) is needed on g++ 2.7.x since it does not
283 // support partial specialization. In egcs this should not be
285 debugstream << "automatic " << &i
286 << ", free store " << p << endl;
289 for (int j = 0; j < 200000; ++j) {
291 tmp << "Test" << endl;