is not the channel but the current thread id. To display channel name you will have to setup a formatter that outputs one.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-29
…thx, it works now!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-29
Hi!
As stated in the initial post I'm using a global logger of type channel_logger_mt.
Is there a MACRO beside the BOOST_LOG_SCOPED_LOGGER_TAG to change the channel string of a logger?
For instance: I've two cpp-modules for which I would like to set module-wide (file-wide) a channel name. This means, in case I enter a method of module "A", I want the log records to have the channel string"A" contained. In case I visit a method of modue "B", I want the log records made in this method to have the channel string "B" contained.
Unfortunately the macro (b]BOOST_LOG_SCOPED_LOGGER_TAG seems not to be the suitable solution, as this macro is - in my understanding and tests acknowledged this behavior - just method-scoped!
Okay, I could set manually always the channel manually in each modules class with MyLogger::get().channel("A") but this is to inconvenient for me, as It would be necessary to repeat this for each class which are definined/declared in one single module.
So, I just need a macro, to set module/file-wide the channel.
Thanks for your help so far!
BR
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There is the BOOST_LOG_CHANNEL macro that sets the channel name, but I would suggest you use different loggers per different modules. If you don't have many modules, this approach may turn out to be more efficient, performance-wise.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
So, I just need a macro, to set module/file-wide the channel.
There are no module-wide attributes. If the logger is global, it only has one channel attribute with one value, which, obvoiusly, correspond to a single module at a time. You can either change the value every time you cross the module boundaries, or use module-specific loggers, each having the channel name of the respective module. Depending on your definition of "modules", this can mean dll-local loggers, static loggers or loggers in anonymous namespaces, object-specific loggers, etc.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-29
Hi.
I now this macro. My itention was to set the channel name once. So it wouldn't be anymore necessary to specify for each log record channel name. Actually I'm using a severity_channel_logger_mt logger. This means, I would have to specify for each record the severity level plus the channel name -> redundancy!
Actually I would like prefer to use a global logger, as this make things simple in my software, because I use the command pattern and I have almost 40 different command class. This means, I have to instantiate for each command class a logger as member in case I don't use the global logger approach. The global approach reduces the "complexity".
Any suggestions?
But thank you so far.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Having object-specific loggers don't increase code complexity that much. This is even easier if you have a common base class of all your commands, so that you can add the logger to the base and initialize it with the channel name passed from the derived class. Aside from that the use of the logger is the same. I don't know how appropriate this solution for your case, but I would definitely prefer object-specific loggers to the global one, when possible.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-29
…thanks for your suggestion. You're right regarding the base class and to add a logger instance to the class.
Thx so far.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-31
HI Andrey,
To filter log records by channel name, I'm using the mechanism referenced as "initialization from a settings container" like illustrated in the code snippet below:
/** Boost.Log-specific macro used to define a placeholder for the channel attribute
*/
BOOST_LOG_ATTRIBUTE_KEYWORD(channelPlaceholder, "Channel", std::string)
// Create a backend and attach a couple of streams to it
boost::shared_ptr< sinks::text_ostream_backend > consoleBackend = boost::make_shared< sinks::text_ostream_backend >();
// Output to the standard out stream -> use std::cout
// Output to the standard logging stream -> use std::clog
consoleBackend->add_stream(boost::shared_ptr< std::ostream >(&std::cout, logging::empty_deleter()));
// Enable auto-flushing after each log record written
consoleBackend->auto_flush(true);
// Wrap it into the frontend and register in the core.
// The backend requires synchronization in the frontend.
typedef sinks::synchronous_sink< sinks::text_ostream_backend > console_sink_t;
boost::shared_ptr< console_sink_t > consoleSink(new console_sink_t(consoleBackend));
// Specify the format of the console log records
consoleSink->set_formatter (
expr::stream <<
" " <<
channelPlaceholder <<
expr::smessage
);
// Produce some log records to verify whether channel filtering works as expected
BOOST_LOG_CHANNEL(GlobalLogger::get(), "Network") << "Log record produced by the \"Network\" channel";
BOOST_LOG_CHANNEL(GlobalLogger::get(), "Control") << "Log record produced by the \"Control\" channel";
BOOST_LOG_CHANNEL(GlobalLogger::get(), "Control") << "One more log record produced by the \"Network\" channel";
(….)
}
The same behavior I receive also for my severity type if setting the filter options in the settings container:
// Produce some log records to verify whether channel filtering works as expected
BOOST_LOG_SEV(GlobalLogger::get(), "FATAL") << "FATAL Log record ";
BOOST_LOG_SEV(GlobalLogger::get(), "WARNING") << "WARNING Log ";
BOOST_LOG_SEV(GlobalLogger::get(), "FATAL") << "FATALOne more log record";
(….)
}
I receive no log record outputs for both channel name and severity level filtering.
Is it necessary to specify a filter factory for the channel name (although std::string isn't a "user-defined" type) and the severity (which also a none-user-defined type, its an enum type) to define and add a filter factory?
BR
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-31
…there is an copy-paste error in the post below: In the formatter there is no placeholder defined for the severity attribute…. actually it looks like as stated below:
std::string attributes need not be registered, the library is aware of this type. Enums are user-defined types, so these attributes need to be registered.
Your code doesn't seem to have any obvious mistakes but it's clearly incomplete. I didn't get what severity level type is, you use enums and strings in different places. If you could provide a complete compilable code snippet, so I'm able to reproduce the problem, I could be more helpful.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-31
moment!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-31
Hi.
please find below the complete code which should compile without problems. BTW: The problem with the channel name-based filtering works now fine. Unfortunately the issue persists regarding to the "Severity-based"-filtering.
#include<iostream>#include<fstream>#include<boost/log/common.hpp>#include<boost/log/expressions.hpp>#include<boost/log/sinks/text_file_backend.hpp>#include<boost/log/sinks/text_ostream_backend.hpp>#include<boost/log/sinks/sync_frontend.hpp>#include<boost/log/support/date_time.hpp>#include<boost/log/utility/empty_deleter.hpp>#include<boost/log/utility/setup/settings.hpp>#include<boost/log/utility/setup/from_settings.hpp>#include<boost/log/utility/setup/from_stream.hpp>#include<boost/log/utility/setup/filter_parser.hpp>#include<boost/log/trivial.hpp>namespacelogging=boost::log;namespacesinks=boost::log::sinks;namespacesrc=boost::log::sources;namespaceexpr=boost::log::expressions;namespaceattrs=boost::log::attributes;namespacekeywords=boost::log::keywords;/** * Enumerates the supported severity levels * for logging. */enumLoggingSeverity{/** * Reports operation information while tracing through the code. */SEV_TRACE,//!< SEVERITY_TRACE/** * Reports detailed information, typically of * interest only when diagnosing problems. */SEV_DEBUG,//!< SEVERITY_DEBUG/** * Reports the succeeded execution of service operations. */SEV_INFO,//!< SEVERITY_INFO/** * Reports the succeeded execution of * the service operations but which doesn't * produce the expected results. */SEV_WARNING,//!< SEVERITY_WARNING/** * Reports any error which doesn't stop * the execution of the service but which can * cause undefined behavior if the service is continued. */SEV_ERROR,//!< SEVERITY_ERROR/** * Reports any error that doesn't permit * a reliable execution of the service or any error * which forces the shutdown of the service. */SEV_FATAL//!< SEVERITY_FATAL};/** * Operator is used to put a human-friendly representation of the severity level * log record. */std::ostream&operator<<(std::ostream&strm,LoggingSeveritylevel);/** * User-defined severity and channel logger type. */typedefsrc::severity_channel_logger_mt<LoggingSeverity,// the type of the severity level valuestd::string// the type of the channel name value>MGPLogger_t;/** * Boost.Log specific macro necessary to use a global logger. */BOOST_LOG_GLOBAL_LOGGER(MGPLogger,MGPLogger_t)/** * User-defined macro wraps the Boost.Log-specific one */#define LOG(sev) \ BOOST_LOG_SEV(MGPLogger::get(), sev)/** * Boost.Log-specific macro used to define a placeholder for the severity attribute */BOOST_LOG_ATTRIBUTE_KEYWORD(severityPlaceholder,"Severity",LoggingSeverity)/** * Boost.Log-specific macro used to define a placeholder for the channel attribute */BOOST_LOG_ATTRIBUTE_KEYWORD(channelPlaceholder,"Channel",std::string)std::ostream&operator<<(std::ostream&strm,LoggingSeveritylevel){staticconstchar*strings[]={"TRACE","DEBUG","INFO","WARNING","ERRORR","FATAL"};if(static_cast<std::size_t>(level)<sizeof(strings)/sizeof(*strings))strm<<strings[level];elsestrm<<static_cast<int>(level);returnstrm;}/** * Boost.Log-specific macro to perform to initialize the global logger. */BOOST_LOG_GLOBAL_LOGGER_INIT(MGPLogger,MGPLogger_t){logging::core::get()->add_global_attribute("MGPTLTAG",boost::log::attributes::constant<std::string>("MGP TL"));// Add global attributs (Line ID; Timestamp etc)// logging::add_common_attributes();// ########## Create a text file sink ############# //// Get a pointer to the Boost::Log logging core ofboost::shared_ptr<logging::core>core=logging::core::get();// ########## Create a console Sink ############# //// Create a backend and attach a couple of streams to itboost::shared_ptr<sinks::text_ostream_backend>consoleBackend=boost::make_shared<sinks::text_ostream_backend>();// Output to the standard out stream -> use std::cout// Output to the standard logging stream -> use std::clogconsoleBackend->add_stream(boost::shared_ptr<std::ostream>(&std::cout,logging::empty_deleter()));// Enable auto-flushing after each log record writtenconsoleBackend->auto_flush(true);// Wrap it into the frontend and register in the core.// The backend requires synchronization in the frontend.typedefsinks::synchronous_sink<sinks::text_ostream_backend>console_sink_t;boost::shared_ptr<console_sink_t>consoleSink(newconsole_sink_t(consoleBackend));// Specify the format of the console log recordsconsoleSink->set_formatter(expr::stream<<"["<<expr::attr<std::string>("MGPTLTAG")<<" - "<<expr::format_date_time<boost::posix_time::ptime>("TimeStamp","%d-%m-%Y %H:%M:%S")<<" - "<<//expr::attr< std::string >("Channel") <<channelPlaceholder<<" - "<<expr::attr<LoggingSeverity>("Severity")<<//severityPlaceholder <<"] "<<expr::smessage);core->add_sink(consoleSink);MGPLogger_tlg(keywords::channel="Control",keywords::severity=SEV_INFO);// Specify the channel name on construction, similarly as with the channel_loggerreturnlg;}intmain(void){// Initiate filtering settingslogging::settingssetts;setts["Core"]["DisableLogging"]=false;//setts["Core"]["Filter"] = "%Channel% = Landstrasse"; // <-> Works now fine!setts["Core"]["Filter"]="%Severity% = WARNING";// <- Doesn't work -> so maybe a factory has to be definedlogging::init_from_settings(setts);BOOST_LOG_CHANNEL_SEV(MGPLogger::get(),"Autobahn",SEV_TRACE)<<"Autobahn, SEV_TRACE";BOOST_LOG_CHANNEL_SEV(MGPLogger::get(),"Autobahn",SEV_DEBUG)<<"Autobahn, SEV_DEBUG";BOOST_LOG_CHANNEL_SEV(MGPLogger::get(),"Landstrasse",SEV_INFO)<<"2. Landstrasse, SEV_INFO";BOOST_LOG_CHANNEL_SEV(MGPLogger::get(),"Landstrasse",SEV_WARNING)<<"Landstrasse, SEV_WARNING";return0;}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-05-31
…any ideas Andrey?
Thanks so far!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
As I suggested, you have to register your severity level enum in the library to be able to parse filters with it.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-06-03
Hey Andrey,
thanks for the hint! After the registration of a filter factory for the user-defined type the filtering works as expected.
However another issure pop-up regarding the format of the log record in case the log record is specified with the settings feature as state below:
(...)
setts["Sinks.File.Destination"] = "TextFile";
setts["Sinks.File.FileName"] = "MGPTL_%d%m%Y_%H%M%S_%2N.log";
setts["Sinks.File.Target"] = "LogFiles/";
// Here: this format is not applied -> just the default format is used, which means that just the message is logged.
setts["Sinks.File"]["Format"] = "[%MGPTLTAG% - %TimeStamp% - %Channel% - %Severity%] %Message%";
setts["Sinks.File"]["Filter"] = "%Severity% = INFO";
setts["Sinks.File.RotationSize"] = 1024; // 1 MiB
setts["Sinks.File.AutoFlush"] = false;
setts["Core"]["Filter"] = "%Severity% != INFO & %Channel% = Fun | %Channel% = Bier ";
BOOST_LOG_CHANNEL_SEV(chanSevLogger, "Fun", SEV_TRACE) << "SEV_TRACE";
BOOST_LOG_CHANNEL_SEV(chanSevLogger, "Bier", SEV_WARNING) << "SEV_WARNING";
BOOST_LOG_CHANNEL_SEV(chanSevLogger, "Fun", SEV_TRACE) << "SEV_TRACE";
BOOST_LOG_CHANNEL_SEV(chanSevLogger, "Bier", SEV_INFO) << "SEV_INFO";
(...)
In case I use the settings
setts = " %Message%";
for the the formatter I just get the default message in the log file:
SEV_INFO
It is also necessary to specify a formatter factory and to register it afterwards in the core? If I understood the documentation correctly, then this isn't necessary.
Any hints?
Thanks for your help so far!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You have to register filter factory to enable your type support in the filter parser. Similarly, you have to register formatter factory to enable it in the formatter parser.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-06-03
…arrrrrrrggg,
I've found the issue: The boost log documentation seems not to be at the latest state…
The docs are correct, the parameter name is "Format". There was a bug in some early revisions (it was named "Formatter" for some time) but it is fixed in 2.0 release.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-06-03
…good to know.
I've to upgrade to boost log v2.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2013-06-03
Hello Andrey,
currently I'm using boost.log under Windows 7. In case I'm using file rotation and and specifying the "MaxSize" parameter my application crashes after the specified size of the directory containg the log files has been reached.
This means, in the situation where the directory size (here 200 bytes) has been reached, the oldest log file should be deleted/overriden/replaced by boost log in that directory. Unfortunately, the complete application crashed without any exception thrown.
Do you know, what could be the issue?
Greetings!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
I was playing a bit with the latest boost.log version and the tutorial.
In case I test execute the code below:
I receive the following output:
Question:
Why is the channel string ("general") as specified in the global logger macro in the log record stated as a hex-decimal string " ".
For my understanding the following log record should be generated:
Any suggestions?
Thank you in advanced for your help!
Br
…ohh sorry,
the expected log record should of course be:
Connection shut down
BR
is not the channel but the current thread id. To display channel name you will have to setup a formatter that outputs one.
…thx, it works now!
Hi!
As stated in the initial post I'm using a global logger of type channel_logger_mt.
Is there a MACRO beside the BOOST_LOG_SCOPED_LOGGER_TAG to change the channel string of a logger?
For instance: I've two cpp-modules for which I would like to set module-wide (file-wide) a channel name. This means, in case I enter a method of module "A", I want the log records to have the channel string"A" contained. In case I visit a method of modue "B", I want the log records made in this method to have the channel string "B" contained.
Unfortunately the macro (b]BOOST_LOG_SCOPED_LOGGER_TAG seems not to be the suitable solution, as this macro is - in my understanding and tests acknowledged this behavior - just method-scoped!
Okay, I could set manually always the channel manually in each modules class with MyLogger::get().channel("A") but this is to inconvenient for me, as It would be necessary to repeat this for each class which are definined/declared in one single module.
So, I just need a macro, to set module/file-wide the channel.
Thanks for your help so far!
BR
There is the BOOST_LOG_CHANNEL macro that sets the channel name, but I would suggest you use different loggers per different modules. If you don't have many modules, this approach may turn out to be more efficient, performance-wise.
There are no module-wide attributes. If the logger is global, it only has one channel attribute with one value, which, obvoiusly, correspond to a single module at a time. You can either change the value every time you cross the module boundaries, or use module-specific loggers, each having the channel name of the respective module. Depending on your definition of "modules", this can mean dll-local loggers, static loggers or loggers in anonymous namespaces, object-specific loggers, etc.
Hi.
I now this macro. My itention was to set the channel name once. So it wouldn't be anymore necessary to specify for each log record channel name. Actually I'm using a severity_channel_logger_mt logger. This means, I would have to specify for each record the severity level plus the channel name -> redundancy!
Actually I would like prefer to use a global logger, as this make things simple in my software, because I use the command pattern and I have almost 40 different command class. This means, I have to instantiate for each command class a logger as member in case I don't use the global logger approach. The global approach reduces the "complexity".
Any suggestions?
But thank you so far.
Having object-specific loggers don't increase code complexity that much. This is even easier if you have a common base class of all your commands, so that you can add the logger to the base and initialize it with the channel name passed from the derived class. Aside from that the use of the logger is the same. I don't know how appropriate this solution for your case, but I would definitely prefer object-specific loggers to the global one, when possible.
…thanks for your suggestion. You're right regarding the base class and to add a logger instance to the class.
Thx so far.
HI Andrey,
To filter log records by channel name, I'm using the mechanism referenced as "initialization from a settings container" like illustrated in the code snippet below:
BOOST_LOG_GLOBAL_LOGGER_INIT(MGPLogger, MGPLogger_t) {
boost::shared_ptr< logging::core > core = logging::core::get();
// Create a backend and attach a couple of streams to it
boost::shared_ptr< sinks::text_ostream_backend > consoleBackend = boost::make_shared< sinks::text_ostream_backend >();
// Output to the standard out stream -> use std::cout
// Output to the standard logging stream -> use std::clog
consoleBackend->add_stream(boost::shared_ptr< std::ostream >(&std::cout, logging::empty_deleter()));
// Enable auto-flushing after each log record written
consoleBackend->auto_flush(true);
// Wrap it into the frontend and register in the core.
// The backend requires synchronization in the frontend.
typedef sinks::synchronous_sink< sinks::text_ostream_backend > console_sink_t;
boost::shared_ptr< console_sink_t > consoleSink(new console_sink_t(consoleBackend));
// Specify the format of the console log records
consoleSink->set_formatter (
expr::stream <<
" " <<
channelPlaceholder <<
expr::smessage
);
core->add_sink(consoleSink);
src::severity_channel_logger_mt<LoggingSeverity, std::string> lg(keywords::channel = "Control", keywords::severity = SEV_INFO);
return lg;
}
int main(void){
// Initiate filtering settings
logging::settings setts;
setts = false;
setts = "%Channel% = Network";
logging::init_from_settings(setts);
// Produce some log records to verify whether channel filtering works as expected
BOOST_LOG_CHANNEL(GlobalLogger::get(), "Network") << "Log record produced by the \"Network\" channel";
BOOST_LOG_CHANNEL(GlobalLogger::get(), "Control") << "Log record produced by the \"Control\" channel";
BOOST_LOG_CHANNEL(GlobalLogger::get(), "Control") << "One more log record produced by the \"Network\" channel";
(….)
}
The same behavior I receive also for my severity type if setting the filter options in the settings container:
setts = "%Severity% = FATAL";
// Initiate filtering settings
logging::settings setts;
setts = false;
setts = "%Severity% = FATAL";
logging::init_from_settings(setts);
// Produce some log records to verify whether channel filtering works as expected
BOOST_LOG_SEV(GlobalLogger::get(), "FATAL") << "FATAL Log record ";
BOOST_LOG_SEV(GlobalLogger::get(), "WARNING") << "WARNING Log ";
BOOST_LOG_SEV(GlobalLogger::get(), "FATAL") << "FATALOne more log record";
(….)
}
I receive no log record outputs for both channel name and severity level filtering.
Is it necessary to specify a filter factory for the channel name (although std::string isn't a "user-defined" type) and the severity (which also a none-user-defined type, its an enum type) to define and add a filter factory?
BR
…there is an copy-paste error in the post below: In the formatter there is no placeholder defined for the severity attribute…. actually it looks like as stated below:
std::string attributes need not be registered, the library is aware of this type. Enums are user-defined types, so these attributes need to be registered.
Your code doesn't seem to have any obvious mistakes but it's clearly incomplete. I didn't get what severity level type is, you use enums and strings in different places. If you could provide a complete compilable code snippet, so I'm able to reproduce the problem, I could be more helpful.
moment!
Hi.
please find below the complete code which should compile without problems. BTW: The problem with the channel name-based filtering works now fine. Unfortunately the issue persists regarding to the "Severity-based"-filtering.
…any ideas Andrey?
Thanks so far!
As I suggested, you have to register your severity level enum in the library to be able to parse filters with it.
Hey Andrey,
thanks for the hint! After the registration of a filter factory for the user-defined type the filtering works as expected.
However another issure pop-up regarding the format of the log record in case the log record is specified with the settings feature as state below:
In case I use the settings
for the the formatter I just get the default message in the log file:
It is also necessary to specify a formatter factory and to register it afterwards in the core? If I understood the documentation correctly, then this isn't necessary.
Any hints?
Thanks for your help so far!
You have to register filter factory to enable your type support in the filter parser. Similarly, you have to register formatter factory to enable it in the formatter parser.
…arrrrrrrggg,
I've found the issue: The boost log documentation seems not to be at the latest state…
I just changed
to
and now its works!
In the documentation http://boost-log.sourceforge.net/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup it is mentioned to use
, but this won't work.
Instead it is necessary to specify
to trigger the core to use the specified log record format.
Nevertheless, thanks so far!
…so, it isn't necessary to specify a "Formatter" factory for my case, that's why your response is a bit confusing…
the log records are no well formatted, except of the severity level string.
So I've have to specify a new formatter factory for the severty level. But it is still necessary to change the keyword from "Format" to "Formatter".
The docs are correct, the parameter name is "Format". There was a bug in some early revisions (it was named "Formatter" for some time) but it is fixed in 2.0 release.
…good to know.
I've to upgrade to boost log v2.
Hello Andrey,
currently I'm using boost.log under Windows 7. In case I'm using file rotation and and specifying the "MaxSize" parameter my application crashes after the specified size of the directory containg the log files has been reached.
Please consider the code below:
This means, in the situation where the directory size (here 200 bytes) has been reached, the oldest log file should be deleted/overriden/replaced by boost log in that directory. Unfortunately, the complete application crashed without any exception thrown.
Do you know, what could be the issue?
Greetings!