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
11 //#include "DebugStream.h"
14 // Since the current C++ lib in egcs does not have a standard implementation
15 // of basic_streambuf and basic_filebuf we don't have to include this
21 ostream & operator<<(ostream & o, Debug::type t)
26 /** This is a streambuffer that never prints out anything, at least
27 that is the intention. You can call it a no-op streambuffer, and
28 the ostream that uses it will be a no-op stream.
30 class nullbuf : public std::streambuf {
33 virtual int sync() { return 0; }
35 virtual std::streamsize xsputn(char const *, std::streamsize n) {
36 // fakes a purge of the buffer by returning n
40 virtual int overflow(int c = EOF) {
41 // fakes success by returning c
42 return c == EOF ? ' ' : c;
46 /** A streambuf that sends the output to two different streambufs. These
47 can be any kind of streambufs.
49 class teebuf : public std::streambuf {
52 teebuf(std::streambuf * b1, std::streambuf * b2)
53 : std::streambuf(), sb1(b1), sb2(b2) {}
59 return sb1->pubsync();
66 virtual std::streamsize xsputn(char const * p, std::streamsize n) {
69 return sb1->sputn(p, n);
72 return sb1->xsputn(p, n);
76 virtual int overflow(int c = EOF) {
82 return sb1->overflow(c);
93 class debugbuf : public std::streambuf {
96 debugbuf(std::streambuf * b)
97 : std::streambuf(), sb(b) {}
102 return sb->pubsync();
108 virtual std::streamsize xsputn(char const * p, std::streamsize n) {
110 return sb->sputn(p, n);
112 return sb->xsputn(p, n);
116 virtual int overflow(int c = EOF) {
120 return sb->overflow(c);
128 /// So that public parts of DebugStream does not need to know about filebuf
129 struct DebugStream::debugstream_internal {
130 /// Used when logging to file.
134 /// Constructor, sets the debug level to t.
135 DebugStream::DebugStream(Debug::type t)
136 : std::ostream(new debugbuf(std::cerr.rdbuf())),
137 dt(t), nullstream(new nullbuf), internal(0) {}
140 /// Constructor, sets the log file to f, and the debug level to t.
141 DebugStream::DebugStream(char const * f, Debug::type t)
142 : std::ostream(new debugbuf(std::cerr.rdbuf())),
143 dt(t), nullstream(new nullbuf),
144 internal(new debugstream_internal)
146 internal->fbuf.open(f, std::ios::out|std::ios::app);
147 delete rdbuf(new teebuf(std::cerr.rdbuf(),
152 DebugStream::~DebugStream()
154 delete nullstream.rdbuf(0); // Without this we leak
155 delete rdbuf(0); // Without this we leak
160 /// Sets the debugstreams' logfile to f.
161 void DebugStream::logFile(char const * f)
164 internal->fbuf.close();
166 internal = new debugstream_internal;
168 internal->fbuf.open(f, std::ios::out|std::ios::app);
169 delete rdbuf(new teebuf(std::cerr.rdbuf(),
174 #ifdef TEST_DEBUGSTREAM
176 // Example debug stream
177 DebugStream debugstream;
179 int main(int, char **)
182 I have been running some tests on this to see how much overhead
183 this kind of permanent debug code has. My conclusion is: not
184 much. In all, but the most time critical code, this will have
185 close to no impact at all.
187 In the tests that I have run the use of
188 if (debugstream.debugging(DebugStream::INFO))
189 debugstream << "some debug\n";
190 has close to no overhead when the debug level is not
194 debugstream.debug(DebugStream::INFO) << "some debug\n";
195 is also very small when the debug level is not
196 DebugStream::INFO. However the overhead for this will increase
197 if complex debugging information is output.
199 The overhead when the debug level is DebugStream::INFO can be
200 significant, but since we then are running in debug mode it is
203 Why should we use this instead of the class Error that we already
204 have? First of all it uses C++ iostream and constructs, secondly
205 it will be a lot easier to output the debug info that we need
206 without a lot of manual conversions, thirdly we can now use
207 iomanipulators and the complete iostream formatting functions.
208 pluss it will work for all types that have a operator<<
209 defined, and can be used in functors that take a ostream & as
210 parameter. And there should be less need for temporary objects.
211 And one nice bonus is that we get a log file almost for
214 Some of the names are of course open to modifications. I will try
215 to use the names we already use in LyX.
217 // Just a few simple debugs to show how it can work.
218 debugstream << "Debug level set to Debug::NONE\n";
219 if (debugstream.debugging()) {
220 debugstream << "Something must be debugged\n";
222 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
223 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
224 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
225 debugstream.level(Debug::value("INFO"));
226 debugstream << "Setting debug level to Debug::INFO\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.addLevel(Debug::type(Debug::CRIT |
235 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
236 debugstream[Debug::WARN] << "more debug(WARN)\n";
237 debugstream[Debug::INFO] << "even more debug(INFO)\n";
238 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
239 debugstream.delLevel(Debug::INFO);
240 debugstream << "Removing Debug::INFO\n";
241 debugstream[Debug::WARN] << "more debug(WARN)\n";
242 debugstream[Debug::INFO] << "even more debug(INFO)\n";
243 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
244 debugstream.logFile("logfile");
245 debugstream << "Setting logfile to \"logfile\"\n";
246 debugstream << "Value: " << 123 << " " << "12\n";
249 // note: the (void*) is needed on g++ 2.7.x since it does not
250 // support partial specialization. In egcs this should not be
252 debugstream << "automatic " << &i
253 << ", free store " << p << std::endl;
256 for (int j = 0; j < 200000; ++j) {
258 tmp << "Test" << std::endl;