Skip to content

Commit

Permalink
Add (smart) logging facility
Browse files Browse the repository at this point in the history
By means of "Use Debug Log" UCI option it is possible to toggle
the logging of std::cout to file "out.txt" while preserving
the usual output to stdout. There is zero overhead when logging
is disabled and we achieved this without changing a single line
of exsisting code, in particular we still use std::cout as usual.

The idea and part of the code comes from this article:
http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
  • Loading branch information
mcostalba committed Mar 18, 2012
1 parent 2dfc94e commit eb28a68
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
64 changes: 64 additions & 0 deletions src/misc.cpp
Expand Up @@ -39,6 +39,7 @@
#include <iomanip>
#include <iostream>
#include <sstream>
#include <streambuf>

#include "misc.h"
#include "thread.h"
Expand Down Expand Up @@ -105,6 +106,69 @@ void dbg_print() {
}


/// Our fancy logging facility. The trick here is to replace cout.rdbuf() with
/// this one that sends the output both to console and to a file, this allow us
/// to toggle the logging of std::cout to a file while preserving output to
/// stdout and without changing a single line of code! Idea and code from:
/// http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81

class Logger: public streambuf {
public:
typedef char_traits<char> traits_type;
typedef traits_type::int_type int_type;

Logger() : cout_buf(cout.rdbuf()) {}
~Logger() { set(false); }

void set(bool b) {

if (b && !file.is_open())
{
file.open("out.txt", ifstream::out | ifstream::app);
cout.rdbuf(this);
}
else if (!b && file.is_open())
{
cout.rdbuf(cout_buf);
file.close();
}
}

private:
int_type overflow(int_type c) {

if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c);

c = cout_buf->sputc(traits_type::to_char_type(c));

if (!traits_type::eq_int_type(c, traits_type::eof()))
c = file.rdbuf()->sputc(traits_type::to_char_type(c));

return c;
}

int sync() {

int c = cout_buf->pubsync();

if (c != -1)
c = file.rdbuf()->pubsync();

return c;
}

ofstream file;
streambuf* cout_buf;
};

void logger_set(bool b) {

static Logger l;
l.set(b);
}


/// cpu_count() tries to detect the number of CPU cores

int cpu_count() {
Expand Down
2 changes: 2 additions & 0 deletions src/misc.h
Expand Up @@ -60,4 +60,6 @@ class Time {
sys_time_t t;
};

extern void logger_set(bool b);

#endif // !defined(MISC_H_INCLUDED)
2 changes: 2 additions & 0 deletions src/ucioption.cpp
Expand Up @@ -33,6 +33,7 @@ OptionsMap Options; // Global object
namespace {

/// 'On change' actions, triggered by an option's value change
void on_logger(const UCIOption& o) { logger_set(o); }
void on_eval(const UCIOption&) { Eval::init(); }
void on_threads(const UCIOption&) { Threads.read_uci_options(); }
void on_hash_size(const UCIOption& o) { TT.set_size(o); }
Expand All @@ -58,6 +59,7 @@ OptionsMap::OptionsMap() {
int msd = cpus < 8 ? 4 : 7;
OptionsMap& o = *this;

o["Use Debug Log"] = UCIOption(false, on_logger);
o["Use Search Log"] = UCIOption(false);
o["Search Log Filename"] = UCIOption("SearchLog.txt");
o["Book File"] = UCIOption("book.bin");
Expand Down

2 comments on commit eb28a68

@rhalbersma
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using "o" as a parameter with the on_xxx(const UICOption& o) functions is a bit dangerous because of confusion with "0". Why not replace it with "opt" or "option"?

@mcostalba
Copy link
Owner Author

@mcostalba mcostalba commented on eb28a68 Mar 20, 2012 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.