Commit 5a7fa664 authored by Davis King's avatar Davis King

Added a hook to the logger object that lets you set a different kind of

output logging destination (in addition to the std::ostream supported already).

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403093
parent dac8d012
......@@ -22,9 +22,14 @@ namespace dlib
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 (
......@@ -255,6 +260,29 @@ namespace dlib
assign_tables( streambuf_table, name, out_.rdbuf());
}
// ----------------------------------------------------------------------------------------
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);
}
// ----------------------------------------------------------------------------------------
logger::print_header_type logger::global_data::
......@@ -339,7 +367,20 @@ namespace dlib
if (!been_used)
{
log.gd.m.lock();
log.logger_header()(log.out,log.name(),l,log.gd.get_thread_name());
// 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
{
// use the empty_string in hopes that it is generally faster than calling
// str("") since this avoids the construction of a new std::string object.
log.gd.sout.str(log.gd.empty_string);
}
been_used = true;
}
}
......@@ -351,10 +392,19 @@ namespace dlib
)
{
auto_unlock M(log.gd.m);
if (log.auto_flush_enabled)
log.out << std::endl;
if (log.hook.is_set() == false)
{
if (log.auto_flush_enabled)
log.out << std::endl;
else
log.out << "\n";
}
else
log.out << "\n";
{
// call the output hook with all the info regarding this log message.
log.hook(log.name(), l, log.gd.get_thread_name(), log.gd.sout.str());
}
}
// ----------------------------------------------------------------------------------------
......@@ -385,6 +435,7 @@ namespace dlib
// 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);
}
// ----------------------------------------------------------------------------------------
......
......@@ -9,11 +9,13 @@
#include "logger_kernel_abstract.h"
#include <limits>
#include <cstring>
#include <sstream>
#include "../algs.h"
#include "../assert.h"
#include "../uintn.h"
#include "../map.h"
#include "../smart_pointers.h"
#include "../member_function_pointer.h"
namespace dlib
{
......@@ -75,10 +77,16 @@ namespace dlib
- out.rdbuf() == std::cout.rdbuf()
- cur_level == LERROR
- auto_flush_enabled == true
- hook.is_set() == false
CONVENTION
- print_header == logger_header()
- out.rdbuf() == output_streambuf()
- if (hook.is_set() == false) then
- out.rdbuf() == output_streambuf()
- else
- out.rdbuf() == gd.sout.rdbuf()
- output_streambuf() == 0
- cur_level == level()
- logger_name == name()
- auto_flush_enabled == auto_flush()
......@@ -90,6 +98,7 @@ namespace dlib
to a thread when we find that it isn't already in thread_names.
!*/
class logger_stream
{
/*!
......@@ -176,6 +185,9 @@ namespace dlib
friend class logger_stream;
public:
typedef member_function_pointer<const std::string&, const log_level&,
const uint64, const std::string&>::kernel_1a_c hook_mfp;
logger (
const char* name_
);
......@@ -245,7 +257,40 @@ namespace dlib
)
{
auto_mutex M(gd.m);
return out.rdbuf();
// 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 std::string& 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.sout.rdbuf());
gd.loggers.element()->hook = hook;
}
}
gd.set_output_hook(logger_name, hook);
gd.set_output_stream(logger_name, gd.sout);
}
void set_output_stream (
......@@ -257,10 +302,16 @@ namespace dlib
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);
}
typedef void (*print_header_type)(
......@@ -297,6 +348,8 @@ namespace dlib
set<logger*>::kernel_1b loggers;
map<thread_id_type,uint64>::kernel_1b thread_names;
uint64 next_thread_name;
std::ostringstream sout;
const std::string empty_string;
global_data (
);
......@@ -407,6 +460,34 @@ namespace dlib
- #output_streambuf(L) == out_.rdbuf()
!*/
struct output_hook_container
{
hook_mfp val;
map<std::string,scoped_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;
......@@ -439,6 +520,8 @@ namespace dlib
static global_data& get_global_data();
// ------------------------------------------------------------------------------------
friend void set_all_logging_levels (
const log_level& new_level
);
......@@ -447,6 +530,34 @@ namespace dlib
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 std::string& message_to_log)
)
{
logger::hook_mfp hook;
hook.set(object, hook_);
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.sout.rdbuf());
gd.loggers.element()->hook = hook;
}
gd.set_output_stream("",gd.sout);
gd.set_output_hook("",hook);
}
// ------------------------------------------------------------------------------------
global_data& gd;
......@@ -457,6 +568,8 @@ namespace dlib
std::ostream out;
log_level cur_level;
hook_mfp hook;
// restricted functions
logger(const logger&); // copy constructor
......@@ -466,6 +579,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
}
#ifdef NO_MAKEFILE
......
......@@ -12,6 +12,8 @@
namespace dlib
{
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class log_level
......@@ -37,6 +39,8 @@ namespace dlib
char name[20];
};
// ----------------------------------------------------------------------------------------
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");
......@@ -46,6 +50,8 @@ namespace dlib
const log_level LERROR(300 ,"ERROR");
const log_level LFATAL(400 ,"FATAL");
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
void set_all_logging_output_streams (
......@@ -55,10 +61,36 @@ namespace dlib
ensures
- for all loggers L:
- #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
!*/
// ----------------------------------------------------------------------------------------
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 std::string& message_to_log)
);
/*!
ensures
- for all loggers L:
- #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
!*/
// ----------------------------------------------------------------------------------------
void set_all_logging_levels (
const log_level& new_level
);
......@@ -70,6 +102,8 @@ namespace dlib
- std::bad_alloc
!*/
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
void print_default_logger_header (
......@@ -87,6 +121,8 @@ namespace dlib
- prints a string to out in the form: "MS l.name [thread_id] logger_name:"
!*/
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class logger
......@@ -183,9 +219,9 @@ namespace dlib
/*!
ensures
- if (l.priority >= level().priority) then
- returns a logger stream with is_enabled() == true and this
stream will write its output to the streambuf given by
output_streambuf().
- 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
......@@ -228,7 +264,8 @@ namespace dlib
/*!
ensures
- returns true if the output stream is flushed after every logged message.
returns false otherwise.
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 (
......@@ -242,12 +279,48 @@ namespace dlib
- 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 std::string& 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
- returns the output stream buffer that this logger writes all
messages to.
- 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 (
......@@ -257,6 +330,8 @@ namespace dlib
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
!*/
......@@ -284,6 +359,7 @@ namespace dlib
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 (
......@@ -306,6 +382,8 @@ namespace dlib
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment