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
#include #include #include #include #include #include #include #include #include #include #include #include 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
(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
("Severity"); logging::register_simple_filter_factory ("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_timeboost::posix_time::ptime("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << " [" << expr::attr<ESeverityLevel>("Severity") << "] " << expr::attr<string>("Process") << ":" << expr::attrlogging::process_id("ProcessID") << ":" << expr::attrlogging::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