diff options
Diffstat (limited to 'ml/dlib/dlib/logger/logger_kernel_1.cpp')
-rw-r--r-- | ml/dlib/dlib/logger/logger_kernel_1.cpp | 498 |
1 files changed, 498 insertions, 0 deletions
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_ + |