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
24 using std::streamsize;
29 ostream & operator<<(ostream & o, Debug::type t)
34 /** This is a streambuffer that never prints out anything, at least
35 that is the intention. You can call it a no-op streambuffer, and
36 the ostream that uses it will be a no-op stream.
38 class nullbuf : public streambuf {
41 virtual int sync() { return 0; }
43 virtual streamsize xsputn(char const *, streamsize n) {
44 // fakes a purge of the buffer by returning n
48 virtual int overflow(int c = EOF) {
49 // fakes success by returning c
50 return c == EOF ? ' ' : c;
54 /** A streambuf that sends the output to two different streambufs. These
55 can be any kind of streambufs.
57 class teebuf : public streambuf {
60 teebuf(streambuf * b1, streambuf * b2)
61 : streambuf(), sb1(b1), sb2(b2) {}
65 #ifdef MODERN_STL_STREAMS
67 return sb1->pubsync();
74 virtual streamsize xsputn(char const * p, streamsize n) {
75 #ifdef MODERN_STL_STREAMS
77 return sb1->sputn(p, n);
80 return sb1->xsputn(p, n);
84 virtual int overflow(int c = EOF) {
85 #ifdef MODERN_STL_STREAMS
90 return sb1->overflow(c);
101 class debugbuf : public streambuf {
104 debugbuf(streambuf * b)
105 : streambuf(), sb(b) {}
109 #ifdef MODERN_STL_STREAMS
110 return sb->pubsync();
116 virtual streamsize xsputn(char const * p, streamsize n) {
117 #ifdef MODERN_STL_STREAMS
118 return sb->sputn(p, n);
120 return sb->xsputn(p, n);
124 virtual int overflow(int c = EOF) {
125 #ifdef MODERN_STL_STREAMS
128 return sb->overflow(c);
136 /// So that public parts of DebugStream does not need to know about filebuf
137 struct DebugStream::debugstream_internal {
138 /// Used when logging to file.
142 /// Constructor, sets the debug level to t.
143 DebugStream::DebugStream(Debug::type t)
144 : ostream(new debugbuf(cerr.rdbuf())),
145 dt(t), nullstream(new nullbuf), internal(0) {}
148 /// Constructor, sets the log file to f, and the debug level to t.
149 DebugStream::DebugStream(char const * f, Debug::type t)
150 : ostream(new debugbuf(cerr.rdbuf())),
151 dt(t), nullstream(new nullbuf),
152 internal(new debugstream_internal)
154 internal->fbuf.open(f, ios::out|ios::app);
155 delete rdbuf(new teebuf(cerr.rdbuf(),
160 DebugStream::~DebugStream()
162 delete nullstream.rdbuf(0); // Without this we leak
163 delete rdbuf(0); // Without this we leak
168 /// Sets the debugstreams' logfile to f.
169 void DebugStream::logFile(char const * f)
172 internal->fbuf.close();
174 internal = new debugstream_internal;
176 internal->fbuf.open(f, ios::out|ios::app);
177 delete rdbuf(new teebuf(cerr.rdbuf(),
182 #ifdef TEST_DEBUGSTREAM
184 // Example debug stream
185 DebugStream debugstream;
187 int main(int, char **)
190 I have been running some tests on this to see how much overhead
191 this kind of permanent debug code has. My conclusion is: not
192 much. In all, but the most time critical code, this will have
193 close to no impact at all.
195 In the tests that I have run the use of
196 if (debugstream.debugging(DebugStream::INFO))
197 debugstream << "some debug\n";
198 has close to no overhead when the debug level is not
202 debugstream.debug(DebugStream::INFO) << "some debug\n";
203 is also very small when the debug level is not
204 DebugStream::INFO. However the overhead for this will increase
205 if complex debugging information is output.
207 The overhead when the debug level is DebugStream::INFO can be
208 significant, but since we then are running in debug mode it is
211 Why should we use this instead of the class Error that we already
212 have? First of all it uses C++ iostream and constructs, secondly
213 it will be a lot easier to output the debug info that we need
214 without a lot of manual conversions, thirdly we can now use
215 iomanipulators and the complete iostream formatting functions.
216 pluss it will work for all types that have a operator<<
217 defined, and can be used in functors that take a ostream & as
218 parameter. And there should be less need for temporary objects.
219 And one nice bonus is that we get a log file almost for
222 Some of the names are of course open to modifications. I will try
223 to use the names we already use in LyX.
225 // Just a few simple debugs to show how it can work.
226 debugstream << "Debug level set to Debug::NONE\n";
227 if (debugstream.debugging()) {
228 debugstream << "Something must be debugged\n";
230 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
231 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
232 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
233 debugstream.level(Debug::value("INFO"));
234 debugstream << "Setting debug level to Debug::INFO\n";
235 if (debugstream.debugging()) {
236 debugstream << "Something must be debugged\n";
238 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
239 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
240 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
241 debugstream.addLevel(Debug::type(Debug::CRIT |
243 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
244 debugstream[Debug::WARN] << "more debug(WARN)\n";
245 debugstream[Debug::INFO] << "even more debug(INFO)\n";
246 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
247 debugstream.delLevel(Debug::INFO);
248 debugstream << "Removing Debug::INFO\n";
249 debugstream[Debug::WARN] << "more debug(WARN)\n";
250 debugstream[Debug::INFO] << "even more debug(INFO)\n";
251 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
252 debugstream.logFile("logfile");
253 debugstream << "Setting logfile to \"logfile\"\n";
254 debugstream << "Value: " << 123 << " " << "12\n";
257 // note: the (void*) is needed on g++ 2.7.x since it does not
258 // support partial specialization. In egcs this should not be
260 debugstream << "automatic " << &i
261 << ", free store " << p << endl;
264 for (int j = 0; j < 200000; ++j) {
266 tmp << "Test" << endl;