Thanks Leo - I didn't think about doing
my own severity stuff, very interesting.
It turns out, in my example, I needed to send the '
keywords::auto_flush = true' parameter into the
'logging::add_file_log(..)' method. After that, it worked fine -
very weird.
Thanks for sending your example, I may pick some stuff out of it
:)
Cheers
Jarrett
On 03/08/13 07:01 PM, Leo Carreon wrote:
Hi Jarrett,
I commiserate with your struggle in trying to get Boost.Log
going. Sorry, I didn't try building your test program because in
my opinion creating a logger class is not the way to go because
doing so means you loose the flexibility of using stream-like
syntax when logging. Instead all you really need is a function to
initialize Boost.Log and then use Boost.Log's global logger
mechanism.
For example, here is my final test program when I was initially
experimenting with Boost.Log:
#include <iostream>
#include <iomanip>
#include <string>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/attributes/clock.hpp>
#include <boost/log/attributes/current_process_name.hpp>
#include <boost/log/attributes/current_process_id.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/log/utility/setup/filter_parser.hpp>
using namespace std;
namespace logging = boost::log;
namespace keywords = boost::log::keywords;
namespace expr = boost::log::expressions;
namespace attr = boost::log::attributes;
namespace src = boost::log::sources;
#define LFC1_LOG(logger, level) BOOST_LOG_SEV(logger, level)
<< "(" << __FILE__ << ", " << __LINE__
<< ") "
#define LFC1_LOG_TRACE(logger) LFC1_LOG(logger, trace)
#define LFC1_LOG_DEBUG(logger) LFC1_LOG(logger, debug)
#define LFC1_LOG_INFO(logger) LFC1_LOG(logger, info)
#define LFC1_LOG_WARNING(logger) LFC1_LOG(logger, warning)
#define LFC1_LOG_ERROR(logger) LFC1_LOG(logger, error)
static const auto RET_SUCCESS = 0;
static const auto RET_FAIL = 1;
enum ESeverityLevel
{
trace,
debug,
info,
warning,
error
};
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", ESeverityLevel)
static const char* gpStrings[] =
{
"trace",
"debug",
"info",
"warning",
"error"
};
ostream& operator<<(ostream& arStream, const
ESeverityLevel& arLevel)
{
if (arStream.good())
{
if (static_cast<size_t>(arLevel) < sizeof(gpStrings) /
sizeof(*gpStrings))
{
arStream << gpStrings[arLevel];
}
else
{
arStream << static_cast<int>(arLevel);
}
}
return arStream;
}
istream& operator>>(istream& arStream,
ESeverityLevel& arLevel)
{
if (arStream.good())
{
string vLevel;
arStream >> vLevel;
for (unsigned vI = 0; vI < sizeof(gpStrings) /
sizeof(*gpStrings); ++vI)
{
if (vLevel == gpStrings[vI])
{
arLevel = static_cast<ESeverityLevel>(vI);
}
}
}
return arStream;
}
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(SLogger,
src::severity_logger<ESeverityLevel>)
static void gvLoggingInit()
{
// Register a formatter and filter for severity level.
logging::register_simple_formatter_factory<ESeverityLevel,
char>("Severity");
logging::register_simple_filter_factory<ESeverityLevel,
char>("Severity");
// Setup the default values for the log settings.
string vFileName = "logs/log_%Y%m%d_%H%M%S_%3N.log";
int vRotationSize = 1024;
//string vTarget = "logs";
//int vMaxSize = 10 * 1024;
ESeverityLevel vSeverity = warning;
// Add a file log with the given settings.
logging::add_file_log
(
keywords::file_name = vFileName,
keywords::rotation_size = vRotationSize,
//keywords::target = vTarget,
//keywords::max_size = vMaxSize,
//keywords::scan_method = logging::sinks::file::scan_all,
keywords::format = expr::stream
<<
expr::format_date_time<boost::posix_time::ptime>("TimeStamp",
"%Y-%m-%d %H:%M:%S.%f")
<< " ["
<< expr::attr<ESeverityLevel>("Severity")
<< "] "
<< expr::attr<string>("Process")
<< ":"
<< expr::attr<logging::process_id>("ProcessID")
<< ":"
<< expr::attr<logging::thread_id>("ThreadID")
<< " "
<< expr::message
);
// Add the logging attributes that we require.
logging::core_ptr pCore = logging::core::get();
pCore->add_global_attribute("TimeStamp", attr::local_clock());
pCore->add_global_attribute("Process",
attr::current_process_name());
pCore->add_global_attribute("ProcessID",
attr::current_process_id());
pCore->add_global_attribute("ThreadID",
attr::current_thread_id());
pCore->set_filter(severity >= vSeverity);
}
int main()
{
try
{
gvLoggingInit();
src::severity_logger<ESeverityLevel>& rLogger =
SLogger::get();
LFC1_LOG_TRACE(rLogger) << "A trace severity message";
LFC1_LOG_DEBUG(rLogger) << "A debug severity message";
LFC1_LOG_INFO(rLogger) << "An informational severity
message";
LFC1_LOG_WARNING(rLogger) << "A warning severity
message";
LFC1_LOG_ERROR(rLogger) << "An error severity message";
LFC1_LOG_TRACE(rLogger) << "Another trace severity
message";
LFC1_LOG_DEBUG(rLogger) << "Another debug severity
message";
LFC1_LOG_INFO(rLogger) << "Another informational
severity message";
LFC1_LOG_WARNING(rLogger) << "Another warning severity
message";
LFC1_LOG_ERROR(rLogger) << "Another error severity
message";
return RET_SUCCESS;
}
catch (exception& crException)
{
cerr << crException.what() << endl;
return RET_FAIL;
}
catch (...)
{
cerr << "Unknown exception" << endl;
return RET_FAIL;
}
}
My test program above also logs to a file, in fact it uses
rotating log files. It also defines its own severity level, which
requires two functions (operator<< and operator>>) to
be defined and registered (really needed otherwise the severity
level string will not appear in the logs) with Boost.Log. I also
experimented with using a settings file which is not shown in the
above code which I abandoned because I couldn't get the timestamp
formatted the way I want it. You might also notice that I
commented out the part to do with log file collectors because I
encountered an issue with it. I also added my own attributes
instead of adding the common attributes which I didn't all need.
When I implemented the above into an actual application, I split
it into 5 source files containing the following:
1. An include file which declares the severity level enumeration,
the operator<< function and the operator>> function.
This is included by the other 2 include files.
2. A source file which defines the operator<< and
operator>> functions. Build and link this with your
application.
3. An include file which declares the initialization function.
Include this file in your application source file where you are
going to invoke the initialization function.
4. A source file which defines the initialization function. Build
and link this with your application.
5. An include file which defines your own logging macros and
declares the global logger. Include this file in each of your
application source files where you are going to perform logging.
In my case, I added another 2 source files which declare and
define my own settings class. Couldn't use Boost.Log's settings
file for the reason I already mentioned above. These replace the
default settings in my test program above. If you do this too,
you either pass the name of the settings file to the
initialization function or somehow the settings class must know
where to look for the settings file.
I hope this helps.
Kind regards,
Leo
_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users