summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/logger
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/logger')
-rw-r--r--ml/dlib/dlib/logger/extra_logger_headers.cpp40
-rw-r--r--ml/dlib/dlib/logger/extra_logger_headers.h41
-rw-r--r--ml/dlib/dlib/logger/logger_config_file.cpp214
-rw-r--r--ml/dlib/dlib/logger/logger_config_file.h135
-rw-r--r--ml/dlib/dlib/logger/logger_kernel_1.cpp498
-rw-r--r--ml/dlib/dlib/logger/logger_kernel_1.h687
-rw-r--r--ml/dlib/dlib/logger/logger_kernel_abstract.h429
7 files changed, 2044 insertions, 0 deletions
diff --git a/ml/dlib/dlib/logger/extra_logger_headers.cpp b/ml/dlib/dlib/logger/extra_logger_headers.cpp
new file mode 100644
index 000000000..becc1ab2b
--- /dev/null
+++ b/ml/dlib/dlib/logger/extra_logger_headers.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_EXTRA_LOGGER_HEADERs_CPP_
+#define DLIB_EXTRA_LOGGER_HEADERs_CPP_
+
+#include "extra_logger_headers.h"
+#include <ctime>
+#include <cstring>
+
+// ----------------------------------------------------------------------------------------
+
+namespace dlib
+{
+
+ void print_datetime_logger_header (
+ std::ostream& out,
+ const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id
+ )
+ {
+ using namespace std;
+ char* buf;
+
+ time_t t = time(0);
+ buf = ctime(&t);
+ // remove the trailing '\n'
+ size_t size = strlen(buf);
+ buf[size-1] = '\0';
+
+ out << l.name << " (" << buf << ") [" << thread_id << "] " << logger_name << ": ";
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_EXTRA_LOGGER_HEADERs_CPP_
+
+
diff --git a/ml/dlib/dlib/logger/extra_logger_headers.h b/ml/dlib/dlib/logger/extra_logger_headers.h
new file mode 100644
index 000000000..6eb24d84c
--- /dev/null
+++ b/ml/dlib/dlib/logger/extra_logger_headers.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_EXTRA_LOGGER_HEADERs_
+#define DLIB_EXTRA_LOGGER_HEADERs_
+
+#include "logger_kernel_abstract.h"
+#include "logger_kernel_1.h"
+#include <iostream>
+#include <string>
+#include "../uintn.h"
+
+// ----------------------------------------------------------------------------------------
+
+namespace dlib
+{
+
+ void print_datetime_logger_header (
+ std::ostream& out,
+ const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id
+ );
+ /*!
+ requires
+ - is not called more than once at a time (i.e. is not called from multiple
+ threads at the same time).
+ ensures
+ - let DATE be the current date and time (e.g. Thu Aug 31 16:41:52 2006).
+ - prints a string to out in the form: "l.name (DATE) [thread_id] logger_name:"
+ !*/
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#ifdef NO_MAKEFILE
+#include "extra_logger_headers.cpp"
+#endif
+
+#endif // DLIB_EXTRA_LOGGER_HEADERs_
+
diff --git a/ml/dlib/dlib/logger/logger_config_file.cpp b/ml/dlib/dlib/logger/logger_config_file.cpp
new file mode 100644
index 000000000..108f66c8c
--- /dev/null
+++ b/ml/dlib/dlib/logger/logger_config_file.cpp
@@ -0,0 +1,214 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LOGGER_CONFIg_FILE_CPP
+#define DLIB_LOGGER_CONFIg_FILE_CPP
+
+#include "logger_config_file.h"
+#include <string>
+#include "../config_reader.h"
+#include <fstream>
+#include <sstream>
+#include "../error.h"
+#include "../map.h"
+#include "../string.h"
+
+// ----------------------------------------------------------------------------------------
+
+namespace dlib
+{
+
+ namespace logger_config_file_helpers
+ {
+
+// ----------------------------------------------------------------------------------------
+
+ std::ostream& get_file_stream (
+ const std::string& file_name
+ )
+ {
+ using namespace std;
+ static dlib::mutex m;
+ auto_mutex M(m);
+ static dlib::map<string,ostream*>::kernel_1a_c file_map;
+
+ if (file_map.is_in_domain(file_name) == false)
+ {
+ // We won't ever delete this output stream. It should be around for the
+ // entire life of the program so just let the OS take care of it.
+ ostream* fout = new ofstream(file_name.c_str());
+ if (!(*fout))
+ {
+ delete fout;
+ throw error("logger_config: unable to open output file " + file_name);
+ }
+
+ // add this file to our file map
+ string temp(file_name);
+ file_map.add(temp,fout);
+ }
+
+ return *file_map[file_name];
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ log_level string_to_log_level (
+ const std::string& level
+ )
+ {
+ using namespace std;
+ if (level == "LALL" || level == "ALL" || level == "all")
+ return LALL;
+ else if (level == "LNONE" || level == "NONE" || level == "none")
+ return LNONE;
+ else if (level == "LTRACE" || level == "TRACE" || level == "trace")
+ return LTRACE;
+ else if (level == "LDEBUG" || level == "DEBUG" || level == "debug")
+ return LDEBUG;
+ else if (level == "LINFO" || level == "INFO" || level == "info")
+ return LINFO;
+ else if (level == "LWARN" || level == "WARN" || level == "warn")
+ return LWARN;
+ else if (level == "LERROR" || level == "ERROR" || level == "error")
+ return LERROR;
+ else if (level == "LFATAL" || level == "FATAL" || level == "fatal")
+ return LFATAL;
+ else
+ {
+ const int priority = string_cast<int>(level);
+ return log_level(priority,"CONFIG_FILE_DEFINED");
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void configure_sub_blocks (
+ const config_reader& cr,
+ const std::string& name
+ )
+ {
+ using namespace std;
+
+ logger dlog(name.c_str());
+
+ if (cr.is_key_defined("logging_level"))
+ {
+ dlog.set_level(string_to_log_level(cr["logging_level"]));
+ }
+
+ if (cr.is_key_defined("output"))
+ {
+ string output = cr["output"];
+ if (output == "cout")
+ dlog.set_output_stream(cout);
+ else if (output == "cerr")
+ dlog.set_output_stream(cerr);
+ else if (output == "clog")
+ dlog.set_output_stream(clog);
+ else
+ {
+ istringstream sin(output);
+ string one, two, three;
+ sin >> one;
+ sin >> two;
+ sin >> three;
+ if (one == "file" && three.size() == 0)
+ dlog.set_output_stream(get_file_stream(two));
+ else
+ throw error("logger_config: invalid argument to output option: " + output);
+ }
+
+ } // if (cr.is_key_defined("output"))
+
+ // now configure all the sub-blocks
+ std_vector_c<std::string> blocks;
+ cr.get_blocks(blocks);
+ for (unsigned long i = 0; i < blocks.size(); ++i)
+ {
+ configure_sub_blocks(cr.block(blocks[i]), name + "." + blocks[i]);
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ } // namespace
+
+// ----------------------------------------------------------------------------------------
+
+ void configure_loggers_from_file (
+ const std::string& file_name
+ )
+ {
+ std::ifstream fin(file_name.c_str());
+
+ if (!fin)
+ throw logger_config_file_error("logger_config: unable to open config file " + file_name);
+
+ config_reader temp(fin);
+ configure_loggers_from_file(temp);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void configure_loggers_from_file (
+ const config_reader& main_cr
+ )
+ {
+ using namespace logger_config_file_helpers;
+ using namespace std;
+
+ if (main_cr.is_block_defined("logger_config"))
+ {
+ const config_reader& cr = main_cr.block("logger_config");
+
+ if (cr.is_key_defined("logging_level"))
+ {
+ set_all_logging_levels(string_to_log_level(cr["logging_level"]));
+ }
+
+ if (cr.is_key_defined("output"))
+ {
+ string output = cr["output"];
+ if (output == "cout")
+ set_all_logging_output_streams(cout);
+ else if (output == "cerr")
+ set_all_logging_output_streams(cerr);
+ else if (output == "clog")
+ set_all_logging_output_streams(clog);
+ else
+ {
+ istringstream sin(output);
+ string one, two, three;
+ sin >> one;
+ sin >> two;
+ sin >> three;
+ if (one == "file" && three.size() == 0)
+ set_all_logging_output_streams(get_file_stream(two));
+ else
+ throw logger_config_file_error("logger_config: invalid argument to output option: " + output);
+ }
+
+ } // if (cr.is_key_defined("output"))
+
+ // now configure all the sub-blocks
+ std_vector_c<std::string> blocks;
+ cr.get_blocks(blocks);
+ for (unsigned long i = 0; i < blocks.size(); ++i)
+ {
+ configure_sub_blocks(cr.block(blocks[i]), blocks[i]);
+ }
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LOGGER_CONFIg_FILE_CPP
+
+
+
diff --git a/ml/dlib/dlib/logger/logger_config_file.h b/ml/dlib/dlib/logger/logger_config_file.h
new file mode 100644
index 000000000..b0a030f80
--- /dev/null
+++ b/ml/dlib/dlib/logger/logger_config_file.h
@@ -0,0 +1,135 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LOGGER_CONFIg_FILE_
+#define DLIB_LOGGER_CONFIg_FILE_
+
+#include "logger_kernel_abstract.h"
+#include "logger_kernel_1.h"
+#include <string>
+#include "../config_reader.h"
+
+// ----------------------------------------------------------------------------------------
+
+namespace dlib
+{
+ class logger_config_file_error : public error
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This is the exception class used by the configure_loggers_from_file()
+ function defined below.
+ !*/
+ public:
+ logger_config_file_error(const std::string& s):error(s){}
+ };
+
+ void configure_loggers_from_file (
+ const std::string& file_name
+ );
+ /*!
+ ensures
+ - configures the loggers with the contents of the file_name file
+ throws
+ - dlib::logger_config_file_error
+ this exception is thrown if there is a problem reading the config file
+ !*/
+
+ void configure_loggers_from_file (
+ const config_reader& cr
+ );
+ /*!
+ ensures
+ - configures the loggers with the contents of cr. This function is just like
+ the above version that reads from a file except that it reads from an in-memory
+ config_reader instead.
+ throws
+ - dlib::logger_config_file_error
+ this exception is thrown if there is a problem reading the config file
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ /*!
+ # -----------------------------------------------
+ # ------------- EXAMPLE CONFIG FILE -------------
+ # -----------------------------------------------
+
+ # The overall format of the config file is the same as the one defined by
+ # the config_reader component of this library.
+
+ # This line is a comment line
+
+ # The config file always has a block named logger_config. This is where all the
+ # config data for the loggers reside.
+ logger_config
+ {
+ # This sets all loggers to the level LINFO since it is just inside the
+ # logger_config block
+ logging_level = info
+
+ # Alternatively we could specify a user defined logging level by
+ # supplying a priority number. The following line would specify
+ # that only logging levels at or above 100 are printed. (note that
+ # you would have to comment out the logging_level statement above
+ # to avoid a conflict).
+ # logging_level = 100
+
+ parent_logger
+ {
+ # This sets all loggers named "parent_logger" or children of
+ # loggers with that name to not log at all (i.e. to logging level
+ # LNONE).
+ logging_level = none
+ }
+
+
+ parent_logger2
+ {
+ # set loggers named "parent_logger2" and its children loggers
+ # to write their output to a file named out.txt
+ output = file out.txt
+
+ child_logger
+ {
+ # Set loggers named "parent_logger2.child_logger" and children of loggers
+ # with this name to logging level LALL
+ logging_level = all
+
+ # Note that this logger will also log to out.txt because that is what
+ # its parent does and we haven't overridden it here with something else.
+ # if we wanted this logger to write to cout instead we could uncomment
+ # the following line:
+ # output = cout
+ }
+ }
+ }
+
+ # So in summary, all logger config stuff goes inside a block named logger_config. Then
+ # inside that block all blocks must be the names of loggers. There are only two keys,
+ # logging_level and output.
+ #
+ # The valid values of logging_level are:
+ # "LALL", "LNONE", "LTRACE", "LDEBUG", "LINFO", "LWARN", "LERROR", "LFATAL",
+ # "ALL", "NONE", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL",
+ # "all", "none", "trace", "debug", "info", "warn", "error", "fatal", or
+ # any integral value
+ #
+ # The valid values of output are:
+ # "cout", "cerr", "clog", or a string of the form "file some_file_name"
+ # which causes the output to be logged to the specified file.
+ #
+ !*/
+
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#ifdef NO_MAKEFILE
+#include "logger_config_file.cpp"
+#endif
+
+#endif // DLIB_LOGGER_CONFIg_FILE_
+
+
+
diff --git a/ml/dlib/dlib/logger/logger_kernel_1.cpp b/ml/dlib/dlib/logger/logger_kernel_1.cpp
new file mode 100644
index 000000000..093cd29a8
--- /dev/null
+++ b/ml/dlib/dlib/logger/logger_kernel_1.cpp
@@ -0,0 +1,498 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LOGGER_KERNEL_1_CPp_
+#define DLIB_LOGGER_KERNEL_1_CPp_
+
+#include "logger_kernel_1.h"
+#include <iostream>
+#include <sstream>
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ void set_all_logging_output_streams (
+ std::ostream& out_
+ )
+ {
+ logger::global_data& gd = logger::get_global_data();
+ auto_mutex M(gd.m);
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ gd.loggers.element()->out.rdbuf(out_.rdbuf());
+ gd.loggers.element()->hook.clear();
+ }
+
+ gd.set_output_stream("",out_);
+
+ // set the default hook to be an empty member function pointer
+ logger::hook_mfp hook;
+ gd.set_output_hook("",hook);
+ }
+
+ void set_all_logging_levels (
+ const log_level& new_level
+ )
+ {
+ logger::global_data& gd = logger::get_global_data();
+ auto_mutex M(gd.m);
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ gd.loggers.element()->cur_level = new_level;
+ }
+
+ gd.set_level("",new_level);
+ }
+
+ void set_all_logging_headers (
+ const print_header_type& new_header
+ )
+ {
+ logger::global_data& gd = logger::get_global_data();
+ auto_mutex M(gd.m);
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ gd.loggers.element()->print_header = new_header;
+ }
+
+ gd.set_logger_header("",new_header);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ namespace logger_helper_stuff
+ {
+ class helper
+ {
+ public:
+ helper()
+ {
+ std::ostringstream sout;
+ print_default_logger_header(sout,"some_name",LDEBUG,0);
+ }
+ };
+ // do this to make sure all the static members of print_default_logger_header get
+ // initialized when the program turns on.
+ static helper a;
+ // make a logger to make extra sure the static global_data object gets
+ // initialized before any threads start up. Also do this so that there is always
+ // at least one logger so that the global data won't be deleted until the
+ // program is terminating.
+ static logger log("dlib");
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void print_default_logger_header (
+ std::ostream& out,
+ const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id
+ )
+ {
+ using namespace std;
+ static timestamper ts;
+ static const uint64 first_time = ts.get_timestamp();
+
+ const uint64 cur_time = (ts.get_timestamp() - first_time)/1000;
+ streamsize old_width = out.width(); out.width(5);
+ out << cur_time << " " << l.name;
+ out.width(old_width);
+
+ out << " [" << thread_id << "] " << logger_name << ": ";
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// global_data stuff
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ logger::global_data::
+ ~global_data (
+ )
+ {
+ unregister_thread_end_handler(*this,&global_data::thread_end_handler);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ logger::global_data::
+ global_data(
+ ) :
+ next_thread_name(1)
+ {
+ // make sure the main program thread always has id 0. Since there is
+ // a global logger object declared in this file we should expect that
+ // the global_data object will be initialized in the main program thread
+ // so if we call get_thread_id() now we should get the main thread id.
+ thread_id_type main_id = get_thread_id();
+ uint64 id_zero = 0;
+ thread_names.add(main_id,id_zero);
+
+ // set up the defaults
+ auto_flush_table.val = true;
+ streambuf_table.val = std::cout.rdbuf();
+ header_table.val = print_default_logger_header;
+
+ // also allocate an initial buffer for hook based logging
+ hookbuf.buffer.reserve(1000);
+ }
+
+ logger::global_data::level_container::
+ level_container (
+ ) : val(300,"ERROR") {}
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ const T& search_tables (
+ const T& c,
+ const std::string& name
+ )
+ {
+ if (c.table.size() == 0 || name.size() == 0)
+ return c;
+
+ const std::string::size_type pos = name.find_first_of(".");
+ const std::string first = name.substr(0,pos);
+ std::string last;
+ if (pos != std::string::npos)
+ last = name.substr(pos+1);
+
+ if (c.table.is_in_domain(first))
+ {
+ return search_tables(*c.table[first], last);
+ }
+ else
+ {
+ return c;
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T, typename U>
+ void assign_tables (
+ T& c,
+ const std::string& name,
+ const U& val
+ )
+ {
+ if (name.size() == 0)
+ {
+ c.val = val;
+ c.table.clear();
+ return;
+ }
+
+ const std::string::size_type pos = name.find_first_of(".");
+ std::string first = name.substr(0,pos);
+ std::string last;
+ if (pos != std::string::npos)
+ last = name.substr(pos+1);
+
+ if (c.table.is_in_domain(first))
+ {
+ assign_tables(*c.table[first], last, val);
+ }
+ else
+ {
+ std::unique_ptr<T> temp (new T);
+ temp->val = c.val;
+ assign_tables(*temp, last, val);
+ c.table.add(first,temp);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ const log_level logger::global_data::
+ level (
+ const std::string& name
+ ) const
+ {
+ auto_mutex M(m);
+ return search_tables(level_table, name).val;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void logger::global_data::
+ set_level (
+ const std::string& name,
+ const log_level& new_level
+ )
+ {
+ auto_mutex M(m);
+ assign_tables(level_table, name, new_level);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ bool logger::global_data::
+ auto_flush (
+ const std::string& name
+ ) const
+ {
+ auto_mutex M(m);
+ return search_tables(auto_flush_table, name).val;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void logger::global_data::
+ set_auto_flush (
+ const std::string& name,
+ bool enabled
+ )
+ {
+ auto_mutex M(m);
+ assign_tables(auto_flush_table, name, enabled);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ std::streambuf* logger::global_data::
+ output_streambuf (
+ const std::string& name
+ )
+ {
+ auto_mutex M(m);
+ return search_tables(streambuf_table, name).val;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void logger::global_data::
+ set_output_stream (
+ const std::string& name,
+ std::ostream& out_
+ )
+ {
+ auto_mutex M(m);
+ assign_tables( streambuf_table, name, out_.rdbuf());
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void logger::global_data::
+ set_output_stream (
+ const std::string& name,
+ std::streambuf& buf
+ )
+ {
+ auto_mutex M(m);
+ assign_tables( streambuf_table, name, &buf);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ logger::hook_mfp logger::global_data::
+ output_hook (
+ const std::string& name
+ )
+ {
+ auto_mutex M(m);
+ return search_tables(hook_table, name).val;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void logger::global_data::
+ set_output_hook (
+ const std::string& name,
+ const hook_mfp& hook
+ )
+ {
+ auto_mutex M(m);
+ assign_tables( hook_table, name, hook);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ print_header_type logger::global_data::
+ logger_header (
+ const std::string& name
+ )
+ {
+ auto_mutex M(m);
+ return search_tables(header_table, name).val;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void logger::global_data::
+ set_logger_header (
+ const std::string& name,
+ print_header_type ph
+ )
+ {
+ auto_mutex M(m);
+ assign_tables(header_table, name, ph);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ logger::global_data& logger::get_global_data()
+ {
+ // Allocate the global_data on the heap rather than on the stack because
+ // we want to guard against the case where this static object would be destroyed
+ // during program termination BEFORE all logger objects are destroyed.
+ static global_data* gd = new global_data;
+ return *gd;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void logger::global_data::
+ thread_end_handler (
+ )
+ {
+ auto_mutex M(m);
+ thread_id_type id = get_thread_id();
+ thread_id_type junkd;
+ uint64 junkr;
+ thread_names.remove(id,junkd,junkr);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ uint64 logger::global_data::
+ get_thread_name (
+ )
+ {
+ thread_id_type id = get_thread_id();
+ uint64 thread_name;
+ if (thread_names.is_in_domain(id))
+ {
+ thread_name = thread_names[id];
+ }
+ else
+ {
+ if (is_dlib_thread(id))
+ register_thread_end_handler(*this,&global_data::thread_end_handler);
+ thread_name = next_thread_name;
+ thread_names.add(id,thread_name);
+ thread_name = next_thread_name;
+ ++next_thread_name;
+ }
+ return thread_name;
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// logger_stream stuff
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ void logger::logger_stream::
+ print_header_and_stuff (
+ )
+ {
+ if (!been_used)
+ {
+ log.gd.m.lock();
+
+ // Check if the output hook is setup. If it isn't then we print the logger
+ // header like normal. Otherwise we need to remember to clear out the output
+ // stringstream we always write to.
+ if (log.hook.is_set() == false)
+ {
+ log.logger_header()(log.out,log.name(),l,log.gd.get_thread_name());
+ }
+ else
+ {
+ // Make sure the hook buffer doesn't have any old data in it before we start
+ // logging a new message into it.
+ log.gd.hookbuf.buffer.resize(0);
+ }
+ been_used = true;
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void logger::logger_stream::
+ print_end_of_line (
+ )
+ {
+ auto_unlock M(log.gd.m);
+
+ if (log.hook.is_set() == false)
+ {
+ if (log.auto_flush_enabled)
+ log.out << std::endl;
+ else
+ log.out << "\n";
+ }
+ else
+ {
+ // Make sure the buffer is a proper C-string
+ log.gd.hookbuf.buffer.push_back('\0');
+ // call the output hook with all the info regarding this log message.
+ log.hook(log.name(), l, log.gd.get_thread_name(), &log.gd.hookbuf.buffer[0]);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// logger stuff
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ logger::
+ logger (
+ const std::string& name_
+ ) :
+ gd(get_global_data()),
+ logger_name(name_),
+ out(gd.output_streambuf(logger_name)),
+ cur_level(gd.level(logger_name))
+ {
+ DLIB_ASSERT(name_[0] != '\0',
+ "\tlogger::logger()"
+ << "\n\tYou can't make a logger with an empty name"
+ << "\n\tthis: " << this
+ );
+
+ auto_mutex M(gd.m);
+ logger* temp = this;
+ gd.loggers.add(temp);
+
+ // load the appropriate settings
+ print_header = gd.logger_header(logger_name);
+ auto_flush_enabled = gd.auto_flush(logger_name);
+ hook = gd.output_hook(logger_name);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ logger::
+ ~logger (
+ )
+ {
+ gd.m.lock();
+ gd.loggers.destroy(this);
+ // if this was the last logger then delete the global data
+ if (gd.loggers.size() == 0)
+ {
+ gd.m.unlock();
+ delete &gd;
+ }
+ else
+ {
+ gd.m.unlock();
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_LOGGER_KERNEL_1_CPp_
+
diff --git a/ml/dlib/dlib/logger/logger_kernel_1.h b/ml/dlib/dlib/logger/logger_kernel_1.h
new file mode 100644
index 000000000..528bd6f67
--- /dev/null
+++ b/ml/dlib/dlib/logger/logger_kernel_1.h
@@ -0,0 +1,687 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LOGGER_KERNEl_1_
+#define DLIB_LOGGER_KERNEl_1_
+
+#include <limits>
+#include <memory>
+#include <cstring>
+#include <streambuf>
+#include <vector>
+
+#include "../threads.h"
+#include "../misc_api.h"
+#include "../set.h"
+#include "logger_kernel_abstract.h"
+#include "../algs.h"
+#include "../assert.h"
+#include "../uintn.h"
+#include "../map.h"
+#include "../member_function_pointer.h"
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ class log_level
+ {
+ public:
+ log_level(
+ int priority_,
+ const char* name_
+ ) :
+ priority(priority_)
+ {
+ strncpy(name,name_,19);
+ name[19] = '\0';
+ }
+
+ bool operator< (const log_level& rhs) const { return priority < rhs.priority; }
+ bool operator<=(const log_level& rhs) const { return priority <= rhs.priority; }
+ bool operator> (const log_level& rhs) const { return priority > rhs.priority; }
+ bool operator>=(const log_level& rhs) const { return priority >= rhs.priority; }
+
+ int priority;
+ char name[20];
+ };
+
+ inline std::ostream& operator<< (std::ostream& out, const log_level& item)
+ {
+ out << item.name;
+ return out;
+ }
+
+ const log_level LALL (std::numeric_limits<int>::min(),"ALL");
+ const log_level LNONE (std::numeric_limits<int>::max(),"NONE");
+ const log_level LTRACE(-100,"TRACE");
+ const log_level LDEBUG(0 ,"DEBUG");
+ const log_level LINFO (100,"INFO ");
+ const log_level LWARN (200,"WARN ");
+ const log_level LERROR(300,"ERROR");
+ const log_level LFATAL(400,"FATAL");
+
+// ----------------------------------------------------------------------------------------
+
+ void set_all_logging_output_streams (
+ std::ostream& out
+ );
+
+ void set_all_logging_levels (
+ const log_level& new_level
+ );
+
+ typedef void (*print_header_type)(
+ std::ostream& out,
+ const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id
+ );
+
+ void set_all_logging_headers (
+ const print_header_type& new_header
+ );
+
+// ----------------------------------------------------------------------------------------
+
+ void print_default_logger_header (
+ std::ostream& out,
+ const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id
+ );
+
+ template <
+ typename T
+ >
+ void set_all_logging_output_hooks (
+ T& object,
+ void (T::*hook_)(const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id,
+ const char* message_to_log)
+ );
+
+ template <
+ typename T
+ >
+ void set_all_logging_output_hooks (
+ T& object
+ )
+ {
+ set_all_logging_output_hooks(object, &T::log);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class logger
+ {
+ /*!
+ INITIAL VALUE
+ - print_header == print_default_logger_header
+ - out.rdbuf() == std::cout.rdbuf()
+ - cur_level == LERROR
+ - auto_flush_enabled == true
+ - hook.is_set() == false
+
+ CONVENTION
+ - print_header == logger_header()
+ - if (hook.is_set() == false) then
+ - out.rdbuf() == output_streambuf()
+ - else
+ - out.rdbuf() == &gd.hookbuf
+ - output_streambuf() == 0
+
+ - cur_level == level()
+ - logger_name == name()
+ - auto_flush_enabled == auto_flush()
+
+ - logger::gd::loggers == a set containing all currently existing loggers.
+ - logger::gd::m == the mutex used to lock everything in the logger
+ - logger::gd::thread_names == a map of thread ids to thread names.
+ - logger::gd::next_thread_name == the next thread name that will be given out
+ to a thread when we find that it isn't already in thread_names.
+ !*/
+
+ // ------------------------------------------------------------------------------------
+ // ------------------------------------------------------------------------------------
+
+ class logger_stream
+ {
+ /*!
+ INITIAL VALUE
+ - been_used == false
+
+ CONVENTION
+ - enabled == is_enabled()
+ - if (been_used) then
+ - logger::gd::m is locked
+ - someone has used the << operator to write something to the
+ output stream.
+ !*/
+ public:
+ logger_stream (
+ const log_level& l_,
+ logger& log_
+ ) :
+ l(l_),
+ log(log_),
+ been_used(false),
+ enabled (l.priority >= log.cur_level.priority)
+ {}
+
+ inline ~logger_stream(
+ )
+ {
+ if (!been_used)
+ {
+ return;
+ }
+ else
+ {
+ print_end_of_line();
+ }
+ }
+
+ bool is_enabled (
+ ) const { return enabled; }
+
+ template <typename T>
+ inline logger_stream& operator << (
+ const T& item
+ )
+ {
+ if (!enabled)
+ {
+ return *this;
+ }
+ else
+ {
+ print_header_and_stuff();
+ log.out << item;
+ return *this;
+ }
+ }
+
+ private:
+
+ void print_header_and_stuff (
+ );
+ /*!
+ ensures
+ - if (!been_used) then
+ - prints the logger header
+ - locks log.gd.m
+ - #been_used == true
+ !*/
+
+ void print_end_of_line (
+ );
+ /*!
+ ensures
+ - prints a newline to log.out
+ - unlocks log.gd.m
+ !*/
+
+ const log_level& l;
+ logger& log;
+ bool been_used;
+ const bool enabled;
+ }; // end of class logger_stream
+
+ // ------------------------------------------------------------------------------------
+ // ------------------------------------------------------------------------------------
+
+ friend class logger_stream;
+ public:
+
+ typedef member_function_pointer<const std::string&, const log_level&,
+ const uint64, const char*> hook_mfp;
+
+ logger (
+ const std::string& name_
+ );
+
+ virtual ~logger (
+ );
+
+ const std::string& name (
+ ) const { return logger_name; }
+
+ logger_stream operator << (
+ const log_level& l
+ ) const { return logger_stream(l,const_cast<logger&>(*this)); }
+
+ bool is_child_of (
+ const logger& log
+ ) const
+ {
+ return (name().find(log.name() + ".") == 0) || (log.name() == name());
+ }
+
+ const log_level level (
+ ) const
+ {
+ auto_mutex M(gd.m);
+ return log_level(cur_level);
+ };
+
+ void set_level (
+ const log_level& new_level
+ )
+ {
+ auto_mutex M(gd.m);
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ if (gd.loggers.element()->is_child_of(*this))
+ gd.loggers.element()->cur_level = new_level;
+ }
+
+ gd.set_level(logger_name, new_level);
+ }
+
+ bool auto_flush (
+ ) const
+ {
+ auto_mutex M(gd.m);
+ return auto_flush_enabled;
+ };
+
+ void set_auto_flush (
+ bool enabled
+ )
+ {
+ auto_mutex M(gd.m);
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ if (gd.loggers.element()->is_child_of(*this))
+ gd.loggers.element()->auto_flush_enabled = enabled;
+ }
+
+ gd.set_auto_flush(logger_name, enabled);
+ }
+
+ std::streambuf* output_streambuf (
+ )
+ {
+ auto_mutex M(gd.m);
+
+ // if there is an output hook set then we are supposed to return 0.
+ if (hook)
+ return 0;
+ else
+ return out.rdbuf();
+ }
+
+ template <
+ typename T
+ >
+ void set_output_hook (
+ T& object,
+ void (T::*hook_)(const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id,
+ const char* message_to_log)
+ )
+ {
+ auto_mutex M(gd.m);
+ hook.set(object, hook_);
+
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ if (gd.loggers.element()->is_child_of(*this))
+ {
+ gd.loggers.element()->out.rdbuf(&gd.hookbuf);
+ gd.loggers.element()->hook = hook;
+ }
+ }
+
+ gd.set_output_hook(logger_name, hook);
+ gd.set_output_stream(logger_name, gd.hookbuf);
+ }
+
+ void set_output_stream (
+ std::ostream& out_
+ )
+ {
+ auto_mutex M(gd.m);
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ if (gd.loggers.element()->is_child_of(*this))
+ {
+ gd.loggers.element()->out.rdbuf(out_.rdbuf());
+ gd.loggers.element()->hook.clear();
+ }
+ }
+
+ gd.set_output_stream(logger_name, out_);
+
+ hook.clear();
+ gd.set_output_hook(logger_name, hook);
+ }
+
+ print_header_type logger_header (
+ ) const { return print_header; }
+
+ void set_logger_header (
+ print_header_type ph
+ )
+ {
+ auto_mutex M(gd.m);
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ if (gd.loggers.element()->is_child_of(*this))
+ gd.loggers.element()->print_header = ph;
+ }
+
+ gd.set_logger_header(logger_name, ph);
+ }
+
+ private:
+
+ // ------------------------------------------------------------------------------------
+ // ------------------------------------------------------------------------------------
+
+ struct global_data
+ {
+ rmutex m;
+ set<logger*>::kernel_1b loggers;
+ map<thread_id_type,uint64>::kernel_1b thread_names;
+ uint64 next_thread_name;
+
+ // Make a very simple streambuf that writes characters into a std::vector<char>. We can
+ // use this as the output target for hooks. The reason we don't just use a std::ostringstream
+ // instead is that this way we can be guaranteed that logging doesn't perform memory allocations.
+ // This is because a std::vector never frees memory. I.e. its capacity() doesn't go down when
+ // you resize it back to 0. It just stays the same.
+ class hook_streambuf : public std::streambuf
+ {
+ public:
+ std::vector<char> buffer;
+ int_type overflow ( int_type c)
+ {
+ if (c != EOF) buffer.push_back(static_cast<char>(c));
+ return c;
+ }
+
+ std::streamsize xsputn ( const char* s, std::streamsize num)
+ {
+ buffer.insert(buffer.end(), s, s+num);
+ return num;
+ }
+ };
+
+ hook_streambuf hookbuf;
+
+ global_data (
+ );
+
+ ~global_data(
+ );
+
+ uint64 get_thread_name (
+ );
+ /*!
+ requires
+ - m is locked
+ ensures
+ - returns a unique id for the calling thread. also makes the number
+ small and nice unlike what you get from get_thread_id()
+ !*/
+
+ void thread_end_handler (
+ );
+ /*!
+ ensures
+ - removes the terminated thread from thread_names
+ !*/
+
+ struct level_container
+ {
+ level_container ();
+
+ log_level val;
+ map<std::string,std::unique_ptr<level_container> >::kernel_1b_c table;
+ } level_table;
+
+ const log_level level (
+ const std::string& name
+ ) const;
+ /*!
+ ensures
+ - returns the level loggers with the given name are supposed
+ to have
+ !*/
+
+ void set_level (
+ const std::string& name,
+ const log_level& new_level
+ );
+ /*!
+ ensures
+ - for all children C of name:
+ - #level(C) == new_level
+ - if name == "" then
+ - for all loggers L:
+ - #level(L) == new_level
+ !*/
+
+ struct auto_flush_container
+ {
+ bool val;
+ map<std::string,std::unique_ptr<auto_flush_container> >::kernel_1b_c table;
+ } auto_flush_table;
+
+ bool auto_flush (
+ const std::string& name
+ ) const;
+ /*!
+ ensures
+ - returns the auto_flush value loggers with the given name are supposed
+ to have
+ !*/
+
+ void set_auto_flush (
+ const std::string& name,
+ bool enabled
+ );
+ /*!
+ ensures
+ - for all children C of name:
+ - #auto_flush_enabled(C) == enabled
+ - if name == "" then
+ - for all loggers L:
+ - #auto_flush_enabled(L) == enabled
+ !*/
+
+ struct output_streambuf_container
+ {
+ std::streambuf* val;
+ map<std::string,std::unique_ptr<output_streambuf_container> >::kernel_1b_c table;
+ } streambuf_table;
+
+ std::streambuf* output_streambuf (
+ const std::string& name
+ );
+ /*!
+ ensures
+ - returns the streambuf loggers with the given name are supposed
+ to have
+ !*/
+
+ void set_output_stream (
+ const std::string& name,
+ std::ostream& out_
+ );
+ /*!
+ ensures
+ - for all children C of name:
+ - #output_streambuf(C) == out_.rdbuf()
+ - if name == "" then
+ - for all loggers L:
+ - #output_streambuf(L) == out_.rdbuf()
+ !*/
+
+ void set_output_stream (
+ const std::string& name,
+ std::streambuf& buf
+ );
+ /*!
+ ensures
+ - for all children C of name:
+ - #output_streambuf(C) == &buf
+ - if name == "" then
+ - for all loggers L:
+ - #output_streambuf(L) == &buf
+ !*/
+
+ struct output_hook_container
+ {
+ hook_mfp val;
+ map<std::string,std::unique_ptr<output_hook_container> >::kernel_1b_c table;
+ } hook_table;
+
+ hook_mfp output_hook (
+ const std::string& name
+ );
+ /*!
+ ensures
+ - returns the hook loggers with the given name are supposed
+ to have
+ !*/
+
+ void set_output_hook (
+ const std::string& name,
+ const hook_mfp& hook
+ );
+ /*!
+ ensures
+ - for all children C of name:
+ - #output_hook(C) == hook
+ - if name == "" then
+ - for all loggers L:
+ - #output_hook(L) == hook
+ !*/
+
+ struct logger_header_container
+ {
+ print_header_type val;
+ map<std::string,std::unique_ptr<logger_header_container> >::kernel_1b_c table;
+ } header_table;
+
+ print_header_type logger_header (
+ const std::string& name
+ );
+ /*!
+ ensures
+ - returns the header function loggers with the given name are supposed
+ to have
+ !*/
+
+ void set_logger_header (
+ const std::string& name,
+ print_header_type ph
+ );
+ /*!
+ ensures
+ - for all children C of name:
+ - #logger_header(C) == ph
+ - if name == "" then
+ - for all loggers L:
+ - #logger_header(L) == ph
+ !*/
+
+ }; // end of struct global_data
+
+ static global_data& get_global_data();
+
+ // ------------------------------------------------------------------------------------
+ // ------------------------------------------------------------------------------------
+
+ friend void set_all_logging_levels (
+ const log_level& new_level
+ );
+
+ friend void set_all_logging_headers (
+ const print_header_type& new_header
+ );
+
+ friend void set_all_logging_output_streams (
+ std::ostream& out
+ );
+
+ template <
+ typename T
+ >
+ friend void set_all_logging_output_hooks (
+ T& object,
+ void (T::*hook_)(const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id,
+ const char* message_to_log)
+ )
+ {
+ logger::hook_mfp hook;
+
+ // There is a bug in one of the versions (but not all apparently) of
+ // Visual studio 2005 that causes it to error out if <T> isn't in the
+ // following line of code. However, there is also a bug in gcc-3.3
+ // that causes it to error out if <T> is present. So this works around
+ // this problem.
+#if defined(_MSC_VER) && _MSC_VER == 1400
+ hook.set<T>(object, hook_);
+#else
+ hook.set(object, hook_);
+#endif
+
+ logger::global_data& gd = logger::get_global_data();
+ auto_mutex M(gd.m);
+ gd.loggers.reset();
+ while (gd.loggers.move_next())
+ {
+ gd.loggers.element()->out.rdbuf(&gd.hookbuf);
+ gd.loggers.element()->hook = hook;
+ }
+
+ gd.set_output_stream("",gd.hookbuf);
+ gd.set_output_hook("",hook);
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ global_data& gd;
+
+ const std::string logger_name;
+
+ print_header_type print_header;
+ bool auto_flush_enabled;
+ std::ostream out;
+ log_level cur_level;
+
+ hook_mfp hook;
+
+
+ // restricted functions
+ logger(const logger&); // copy constructor
+ logger& operator=(const logger&); // assignment operator
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+
+
+
+}
+
+#ifdef NO_MAKEFILE
+#include "logger_kernel_1.cpp"
+#endif
+
+#endif // DLIB_LOGGER_KERNEl_1_
+
diff --git a/ml/dlib/dlib/logger/logger_kernel_abstract.h b/ml/dlib/dlib/logger/logger_kernel_abstract.h
new file mode 100644
index 000000000..b6a4367a2
--- /dev/null
+++ b/ml/dlib/dlib/logger/logger_kernel_abstract.h
@@ -0,0 +1,429 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#undef DLIB_LOGGER_KERNEl_ABSTRACT_
+#ifdef DLIB_LOGGER_KERNEl_ABSTRACT_
+
+#include "../threads.h"
+#include <limits>
+#include <string>
+#include <iostream>
+#include "../uintn.h"
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ class log_level
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object is a simple named level to log at. It contains a numeric
+ priority and a name to use in the logging messages.
+ !*/
+ public:
+ log_level(
+ int priority_,
+ const char* name_
+ );
+ /*!
+ ensures
+ - #priority = priority_
+ - the first 19 characters of name_ are copied into name and name
+ is null terminated.
+ !*/
+
+ bool operator< (const log_level& rhs) const { return priority < rhs.priority; }
+ bool operator<=(const log_level& rhs) const { return priority <= rhs.priority; }
+ bool operator> (const log_level& rhs) const { return priority > rhs.priority; }
+ bool operator>=(const log_level& rhs) const { return priority >= rhs.priority; }
+
+ int priority;
+ char name[20];
+ };
+
+ inline std::ostream& operator<< (std::ostream& out, const log_level& item);
+ /*!
+ ensures
+ - performs out << item.name
+ - returns out
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ const log_level LALL (std::numeric_limits<int>::min(),"ALL");
+ const log_level LNONE (std::numeric_limits<int>::max(),"NONE");
+ const log_level LTRACE(-100,"TRACE");
+ const log_level LDEBUG(0 ,"DEBUG");
+ const log_level LINFO (100 ,"INFO ");
+ const log_level LWARN (200 ,"WARN ");
+ const log_level LERROR(300 ,"ERROR");
+ const log_level LFATAL(400 ,"FATAL");
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ void set_all_logging_output_streams (
+ std::ostream& out
+ );
+ /*!
+ ensures
+ - for all loggers L (even loggers not yet constructed):
+ - #L.output_streambuf() == out.rdbuf()
+ - Removes any previous output hook from L. So now the logger
+ L will write all its messages to the given output stream.
+ throws
+ - std::bad_alloc
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ typedef void (*print_header_type)(
+ std::ostream& out,
+ const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id
+ );
+
+ void set_all_logging_headers (
+ const print_header_type& new_header
+ );
+ /*!
+ ensures
+ - for all loggers L (even loggers not yet constructed):
+ - #L.logger_header() == new_header
+ throws
+ - std::bad_alloc
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ void set_all_logging_output_hooks (
+ T& object,
+ void (T::*hook)(const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id,
+ const char* message_to_log)
+ );
+ /*!
+ ensures
+ - for all loggers L (even loggers not yet constructed):
+ - #L.output_streambuf() == 0
+ - performs the equivalent to calling L.set_output_hook(object, hook);
+ (i.e. sets all loggers so that they will use the given hook function)
+ throws
+ - std::bad_alloc
+ !*/
+
+ template <
+ typename T
+ >
+ void set_all_logging_output_hooks (
+ T& object
+ );
+ /*!
+ ensures
+ - calls set_all_logging_output_hooks(object, &T::log);
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ void set_all_logging_levels (
+ const log_level& new_level
+ );
+ /*!
+ ensures
+ - for all loggers L (even loggers not yet constructed):
+ - #L.level() == new_level
+ throws
+ - std::bad_alloc
+ !*/
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ void print_default_logger_header (
+ std::ostream& out,
+ const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id
+ );
+ /*!
+ requires
+ - is not called more than once at a time (i.e. is not called from multiple
+ threads at the same time).
+ ensures
+ - let MS be the number of milliseconds since program start.
+ - prints a string to out in the form: "MS l.name [thread_id] logger_name:"
+ !*/
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ class logger
+ {
+ /*!
+ INITIAL VALUE
+ - name() == a user supplied value given to the constructor
+ - The values of level(), output_streambuf(), logger_header(), and
+ auto_flush() are inherited from the parent of this logger.
+
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a logging output stream in the style of the log4j
+ logger available for Java.
+
+ Additionally, the logger doesn't perform any memory allocations during
+ each logging action. It just writes directly into the user supplied output
+ stream. Alternatively, if you use a logging output hook no memory allocations
+ are performed either. Logging just goes straight into a memory buffer
+ which gets passed to the user supplied logging hook.
+
+ DEFAULTS
+ If the user hasn't specified values for the four inherited values level(),
+ output_streambuf(), logger_header(), or auto_flush() then the default
+ values will be used. The defaults are as follows:
+ - level() == LERROR
+ - output_streambuf() == std::cout.rdbuf() (i.e. the default is to log
+ to standard output).
+ - logger_header() == print_default_logger_header
+ - auto_flush() == true
+
+ THREAD SAFETY
+ All methods of this class are thread safe. Note that it is safe to
+ chain calls to operator << such as:
+ log << LINFO << "message " << variable << " more message";
+ The logger ensures that the entire statement executes atomically so the
+ message won't be broken up by other loggers in other threads.
+ !*/
+
+ class logger_stream
+ {
+ public:
+
+ bool is_enabled (
+ ) const;
+ /*!
+ ensures
+ - returns true if this logger stream will print out items
+ given to it by the << operator. returns false otherwise.
+ !*/
+
+ template <typename T>
+ logger_stream& operator << (
+ const T& item
+ );
+ /*!
+ ensures
+ - if (is_enabled()) then
+ - writes item to this output stream
+ - returns *this
+ !*/
+ };
+
+ public:
+
+ logger (
+ const std::string& name_
+ );
+ /*!
+ requires
+ - name_ != ""
+ ensures
+ - #*this is properly initialized
+ - #name() == name_
+ throws
+ - std::bad_alloc
+ - dlib::thread_error
+ !*/
+
+ virtual ~logger (
+ );
+ /*!
+ ensures
+ - any resources associated with *this have been released
+ !*/
+
+ const std::string& name (
+ ) const;
+ /*!
+ ensures
+ - returns the name of this logger
+ !*/
+
+ logger_stream operator << (
+ const log_level& l
+ ) const;
+ /*!
+ ensures
+ - if (l.priority >= level().priority) then
+ - returns a logger_stream with is_enabled() == true. I.e. this
+ returned stream will write its output to the I/O destination
+ used by this logger object.
+ - else
+ - returns a logger stream with is_enabled() == false
+ throws
+ - std::bad_alloc
+ !*/
+
+ bool is_child_of (
+ const logger& log
+ ) const;
+ /*!
+ ensures
+ - if ( (name().find(log.name() + ".") == 0) || (log.name() == name()) ) then
+ - returns true
+ (i.e. if log.name() + "." is a prefix of name() or if both *this and log
+ have the same name then return true)
+ - else
+ - returns false
+ !*/
+
+ const log_level level (
+ ) const;
+ /*!
+ ensures
+ - returns the current log level of this logger.
+ !*/
+
+ void set_level (
+ const log_level& new_level
+ );
+ /*!
+ ensures
+ - for all loggers L such that L.is_child_of(*this) == true:
+ - #L.level() == new_level
+ throws
+ - std::bad_alloc
+ !*/
+
+ bool auto_flush (
+ );
+ /*!
+ ensures
+ - returns true if the output stream is flushed after every logged message.
+ returns false otherwise. (Note that flushing only does anything if
+ the logger is set to use an output stream rather than a hook)
+ !*/
+
+ void set_auto_flush (
+ bool enabled
+ );
+ /*!
+ ensures
+ - for all loggers L such that L.is_child_of(*this) == true:
+ - #L.auto_flush() == enabled
+ throws
+ - std::bad_alloc
+ !*/
+
+
+ template <
+ typename T
+ >
+ void set_output_hook (
+ T& object,
+ void (T::*hook)(const std::string& logger_name,
+ const log_level& l,
+ const uint64 thread_id,
+ const char* message_to_log)
+ );
+ /*!
+ requires
+ - hook is a valid pointer to a member function in T
+ ensures
+ - for all loggers L such that L.is_child_of(*this) == true:
+ - #L.output_streambuf() == 0
+ - #L will not send its log messages to an ostream object anymore. Instead
+ it will call the given hook member function (i.e. (object.*hook)(name,l,id,msg) )
+ for each message that needs to be logged.
+ - The arguments to the hook function have the following meanings:
+ - logger_name == The name of the logger that is printing the log message.
+ - l == The level of the logger that is printing the log message.
+ - thread_id == A number that uniquely identifies the thread trying to log
+ the message. Note that this number is unique among all threads, past and
+ present. Also note that this id is not the same one returned by
+ get_thread_id().
+ - message_to_log == the actual text of the message the user is giving to
+ the logger object to log.
+ - All hook functions will also only be called one at a time. This means
+ that hook functions don't need to be thread safe.
+ !*/
+
+ std::streambuf* output_streambuf (
+ );
+ /*!
+ ensures
+ - if (an output hook isn't set) then
+ - returns the output stream buffer that this logger writes all
+ messages to.
+ - else
+ - returns 0
+ !*/
+
+ void set_output_stream (
+ std::ostream& out
+ );
+ /*!
+ ensures
+ - for all loggers L such that L.is_child_of(*this) == true:
+ - #L.output_streambuf() == out.rdbuf()
+ - Removes any previous output hook from L. So now the logger
+ L will write all its messages to the given output stream.
+ throws
+ - std::bad_alloc
+ !*/
+
+ print_header_type logger_header (
+ ) const;
+ /*!
+ ensures
+ - returns the function that is called to print the header information
+ onto each logged message. The arguments to the function have the following
+ meanings:
+ - out == The output stream this function writes the header to.
+ - logger_name == The name of the logger that is printing the log message.
+ - l == The level of the logger that is printing the log message.
+ - thread_id == A number that uniquely identifies the thread trying to log
+ the message. Note that this number is unique among all threads, past and
+ present. Also note that this id is not the same one returned by
+ get_thread_id().
+ - This logger_header function will also only be called once at a time. This means
+ the logger_header function doesn't need to be thread safe.
+ - the logger_header function is only used when output_streambuf() != 0
+ !*/
+
+ void set_logger_header (
+ print_header_type print_header
+ );
+ /*!
+ ensures
+ - for all loggers L such that L.is_child_of(*this) == true:
+ - #L.logger_header() == print_header
+ throws
+ - std::bad_alloc
+ !*/
+
+ private:
+
+ // restricted functions
+ logger(const logger&); // copy constructor
+ logger& operator=(const logger&); // assignment operator
+
+ };
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_LOGGER_KERNEl_ABSTRACT_
+