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 #ifdef MODERN_STL_STREAMS
23 using std::streamsize;
28 ostream & operator<<(ostream & o, Debug::type t)
33 /** This is a streambuffer that never prints out anything, at least
34 that is the intention. You can call it a no-op streambuffer, and
35 the ostream that uses it will be a no-op stream.
37 class nullbuf : public streambuf {
40 virtual int sync() { return 0; }
42 virtual streamsize xsputn(char const *, streamsize n) {
43 // fakes a purge of the buffer by returning n
47 virtual int overflow(int c = EOF) {
48 // fakes success by returning c
49 return c == EOF ? ' ' : c;
53 /** A streambuf that sends the output to two different streambufs. These
54 can be any kind of streambufs.
56 class teebuf : public streambuf {
59 teebuf(streambuf * b1, streambuf * b2)
60 : streambuf(), sb1(b1), sb2(b2) {}
64 #ifdef MODERN_STL_STREAMS
66 return sb1->pubsync();
73 virtual streamsize xsputn(char const * p, streamsize n) {
74 #ifdef MODERN_STL_STREAMS
76 return sb1->sputn(p, n);
79 return sb1->xsputn(p, n);
83 virtual int overflow(int c = EOF) {
84 #ifdef MODERN_STL_STREAMS
89 return sb1->overflow(c);
100 class debugbuf : public streambuf {
103 debugbuf(streambuf * b)
104 : streambuf(), sb(b) {}
108 #ifdef MODERN_STL_STREAMS
109 return sb->pubsync();
115 virtual streamsize xsputn(char const * p, streamsize n) {
116 #ifdef MODERN_STL_STREAMS
117 return sb->sputn(p, n);
119 return sb->xsputn(p, n);
123 virtual int overflow(int c = EOF) {
124 #ifdef MODERN_STL_STREAMS
127 return sb->overflow(c);
135 /// So that public parts of DebugStream does not need to know about filebuf
136 struct DebugStream::debugstream_internal {
137 /// Used when logging to file.
141 /// Constructor, sets the debug level to t.
142 DebugStream::DebugStream(Debug::type t)
143 : ostream(new debugbuf(cerr.rdbuf())),
144 dt(t), nullstream(new nullbuf), internal(0) {}
147 /// Constructor, sets the log file to f, and the debug level to t.
148 DebugStream::DebugStream(char const * f, Debug::type t)
149 : ostream(new debugbuf(cerr.rdbuf())),
150 dt(t), nullstream(new nullbuf),
151 internal(new debugstream_internal)
153 internal->fbuf.open(f, ios::out|ios::app);
154 delete rdbuf(new teebuf(cerr.rdbuf(),
159 DebugStream::~DebugStream()
161 delete nullstream.rdbuf(0); // Without this we leak
162 delete rdbuf(0); // Without this we leak
167 /// Sets the debugstreams' logfile to f.
168 void DebugStream::logFile(char const * f)
171 internal->fbuf.close();
173 internal = new debugstream_internal;
175 internal->fbuf.open(f, ios::out|ios::app);
176 delete rdbuf(new teebuf(cerr.rdbuf(),
181 #ifdef TEST_DEBUGSTREAM
183 // Example debug stream
184 DebugStream debugstream;
186 int main(int, char **)
189 I have been running some tests on this to see how much overhead
190 this kind of permanent debug code has. My conclusion is: not
191 much. In all, but the most time critical code, this will have
192 close to no impact at all.
194 In the tests that I have run the use of
195 if (debugstream.debugging(DebugStream::INFO))
196 debugstream << "some debug\n";
197 has close to no overhead when the debug level is not
201 debugstream.debug(DebugStream::INFO) << "some debug\n";
202 is also very small when the debug level is not
203 DebugStream::INFO. However the overhead for this will increase
204 if complex debugging information is output.
206 The overhead when the debug level is DebugStream::INFO can be
207 significant, but since we then are running in debug mode it is
210 Why should we use this instead of the class Error that we already
211 have? First of all it uses C++ iostream and constructs, secondly
212 it will be a lot easier to output the debug info that we need
213 without a lot of manual conversions, thirdly we can now use
214 iomanipulators and the complete iostream formatting functions.
215 pluss it will work for all types that have a operator<<
216 defined, and can be used in functors that take a ostream & as
217 parameter. And there should be less need for temporary objects.
218 And one nice bonus is that we get a log file almost for
221 Some of the names are of course open to modifications. I will try
222 to use the names we already use in LyX.
224 // Just a few simple debugs to show how it can work.
225 debugstream << "Debug level set to Debug::NONE\n";
226 if (debugstream.debugging()) {
227 debugstream << "Something must be debugged\n";
229 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
230 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
231 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
232 debugstream.level(Debug::value("INFO"));
233 debugstream << "Setting debug level to Debug::INFO\n";
234 if (debugstream.debugging()) {
235 debugstream << "Something must be debugged\n";
237 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
238 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
239 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
240 debugstream.addLevel(Debug::type(Debug::CRIT |
242 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
243 debugstream[Debug::WARN] << "more debug(WARN)\n";
244 debugstream[Debug::INFO] << "even more debug(INFO)\n";
245 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
246 debugstream.delLevel(Debug::INFO);
247 debugstream << "Removing Debug::INFO\n";
248 debugstream[Debug::WARN] << "more debug(WARN)\n";
249 debugstream[Debug::INFO] << "even more debug(INFO)\n";
250 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
251 debugstream.logFile("logfile");
252 debugstream << "Setting logfile to \"logfile\"\n";
253 debugstream << "Value: " << 123 << " " << "12\n";
256 // note: the (void*) is needed on g++ 2.7.x since it does not
257 // support partial specialization. In egcs this should not be
259 debugstream << "automatic " << &i
260 << ", free store " << p << endl;
263 for (int j = 0; j < 200000; ++j) {
265 tmp << "Test" << endl;