#include <boost/log/utility/string_literal.hpp>
String literals are used in several places throughout the library. However, this component can be successfully used outside of the library in users' code. It is header-only and does not require linking with the library binary. String literals can improve performance significantly if there is no need to modify stored strings. What is also important, since string literals do not dynamically allocate memory, it is easier to maintain exception safety when using string literals instead of regular strings.
The functionality is implemented in the basic_string_literal
class template, which is parametrized with the character and character
traits, similar to std::basic_string
.
There are also two convenience typedefs provided: string_literal
and wstring_literal
, for
narrow and wide character types, respectively. In order to ease string
literal construction in generic code there is also a str_literal
function template that accepts a string literal and returns a basic_string_literal
instance for the
appropriate character type.
String literals support interface similar to STL strings, except for string
modification functions. However, it is possible to assign to or clear string
literals, as long as only string literals involved. Relational and stream
output operators are also supported. More detailed information is given
in the Reference section
.
#include <boost/log/utility/type_info_wrapper.hpp>
The language support for run time type information is essential for the
library. But partially because of limitations that the C++ Standard imposes
on this feature, partially because of differences of implementation of
different compilers, there was a need for a lightweight wrapper around
the std::type_info
class to fill the gaps. The
table below briefly shows the differences between the std::type_info
and type_info_wrapper
classes.
Table 1.2. Type information classes comparison
Feature |
|
|
---|---|---|
Is default-constructable |
No |
Yes. The default-constructed wrapper is in an empty state. |
Is copy-constructable |
No |
Yes |
Is assignable |
No |
Yes |
Is swappable |
No |
Yes |
Life time duration |
Static, until the application terminates |
Dynamic |
Has an empty state |
No |
Yes. In empty state the type info wrapper is never equal to other non-empty type info wrappers. It is equal to other empty type info wrappers and can be ordered with them. |
Supports equality comparison |
Yes |
Yes |
Supports ordering |
Yes, partial ordering with the |
Yes, partial ordering with the complete set of comparison operators.
The semantics of ordering is similar to the |
Supports printable representation of type |
Yes, with the |
Yes, with |
Given the distinctions above, using type information objects becomes much
easier. For example, the ability to copy and order with regular operators
allows using type_info_wrapper
with containers. The ability to default-construct and assign allows using
type information as a regular object and not to resort to pointers which
may be unsafe.
#include <boost/log/utility/scoped_attribute.hpp>
Scoped attributes are a powerful mechanism of tagging log records that can be used for different purposes. As the naming implies, scoped attributes are registered in the beginning of a scope and unregistered on the end of the scope. The mechanism includes the following four macros:
BOOST_LOG_SCOPED_LOGGER_ATTR(logger, attr_name, attr_type); BOOST_LOG_SCOPED_LOGGER_ATTR_CTOR(logger, attr_name, attr_type, attr_ctor_args); BOOST_LOG_SCOPED_THREAD_ATTR(attr_name, attr_type); BOOST_LOG_SCOPED_THREAD_ATTR_CTOR(attr_name, attr_type, attr_ctor_args);
The former two register a source-specific attribute in the logger
logger object. The attribute name
and type are given in the attr_name
and attr_type
arguments.
The BOOST_LOG_SCOPED_LOGGER_ATTR_CTOR additionally accepts a Boost.Preprocessor
sequence of arguments that should be passed to the attribute constructor.
The latter pair of macros do exactly the same but the attribute is registered
for the current thread in the logging core (which does not require a logger).
Note | |
---|---|
If an attribute with the same name is already registered in the logger/logging core, the macros won't override the existing attribute and will eventually have no effect. See Rationale for a more detailed explanation of the reasons for such behavior. |
Usage example follows:
BOOST_LOG_DECLARE_GLOBAL_LOGGER(my_logger, src::logger_mt) void foo() { // This log record will also be marked with the "Tag" attribute, // whenever it is called from the A::bar function. // It will not be marked when called from other places. BOOST_LOG(get_my_logger()) << "A log message from foo"; } struct A { src::logger m_Logger; void bar() { // Set a thread-wide markup tag. // Note the additional parentheses to form a Boost.PP sequence. BOOST_LOG_SCOPED_THREAD_ATTR_CTOR("Tag", attrs::constant< std::string >, ("Called from A::bar")); // This log record will be marked BOOST_LOG(m_Logger) << "A log message from A::bar"; foo(); } }; int main(int, char*[]) { src::logger lg; // Let's measure our application run time BOOST_LOG_SCOPED_LOGGER_ATTR(lg, "RunTime", attrs::timer); // Mark application start. // The "RunTime" attribute should be nearly 0 at this point. BOOST_LOG(lg) << "Application started"; // Note that no other log records are affected by the "RunTime" attribute. foo(); A a; a.bar(); // Mark application ending. // The "RunTime" attribute will show the execution time elapsed. BOOST_LOG(lg) << "Application ended"; return 0; }
It is quite often convenient to mark a group of log records with a constant value in order to be able to filter the records later. The library provides two convenience macros just for this purpose:
BOOST_LOG_SCOPED_LOGGER_TAG(logger, tag_name, tag_type, tag_value); BOOST_LOG_SCOPED_THREAD_TAG(tag_name, tag_type, tag_value);
The macros are effectively wrappers around BOOST_LOG_SCOPED_LOGGER_ATTR_CTOR
and BOOST_LOG_SCOPED_THREAD_ATTR_CTOR
,
respectively. For example, the "Tag" scoped attribute from the
example above can be registered like this:
// Note there is no "attrs::constant" type wrapping // and no additional parenthesis around the tag value. BOOST_LOG_SCOPED_THREAD_TAG("Tag", std::string, "Called from A::bar");
Warning | |
---|---|
When using scoped attributes, make sure that the scoped attribute is not altered in the attribute set in which it was registered. For example, one should not clear or reinstall the attribute set of the logger if there are logger-specific scoped attributes registered in it. Otherwise the program will likely crash. This issue is especially critical in multithreaded application, when one thread may not know whether there are scoped attributes in the logger or there are not. Future releases may solve this limitation but currently the scoped attribute must remain intact until unregistered on leaving the scope. |
Although the described macros are intended to be the primary interface for the functionality, there is also a C++ interface available. It may be useful if the user decides to develop his own macros that cannot be based on the existing ones.
Any scoped attribute is attached to a generic sentry object of type scoped_attribute
. As long as the sentry
exists, the attribute is registered. There are several functions that create
sentries for source or thread-specific attributes:
// Source-specific scoped attribute registration template< typename LoggerT > [unspecified] add_scoped_logger_attribute( LoggerT& l, typename LoggerT::string_type const& name, shared_ptr< attribute > const& attr); template< typename LoggerT, typename AttributeT > [unspecified] add_scoped_logger_attribute( LoggerT& l, typename LoggerT::string_type const& name, AttributeT& attr); // Thread-specific scoped attribute registration template< typename CharT > [unspecified] add_scoped_thread_attribute( std::basic_string< CharT > const& name, shared_ptr< attribute > const& attr); template< typename CharT, typename AttributeT > [unspecified] add_scoped_thread_attribute( std::basic_string< CharT > const& name, AttributeT& attr);
Please note that the overloads that accept references to the attribute do not control the life time of the attribute. These overloads can be used to temporarily register attributes that reside on stack or are members of a class - in other words, whose life duration is controlled elsewhere.
An object of the scoped_attribute
type is able to attach results of each of these functions on its construction.
For example, BOOST_LOG_SCOPED_LOGGER_ATTR(lg,
"RunTime",
attrs::timer)
can roughly be expanded to this:
attrs::timer attr; attrs::scoped_attribute sentry = attrs::add_scoped_logger_attribute(lg, "RunTime", attr);
#include <boost/log/utility/type_dispatch/type_dispatcher.hpp>
Type dispatchers are used throughout the library in order to work with attribute values. Dispatchers allow acquiring the actual typed attribute value using the Visitor concept. The most notable places where the functionality is used are filters and formatters. However, this mechanism is orthogonal to attributes and can be used for other purposes as well. Most of the time users won't need to dig into the details of type dispatchers, but this information may be useful for those who intend to extend the library and wants to understand what's under the hood.
Every type dispatcher supports the type_dispatcher
interface. When an attribute value needs to be extracted, this interface
is passed to the attribute value object, which then tries to acquire the
concrete visitor for the actual type of the value. All visitors derive
from the appropriate instance of the type_visitor
class template, instantiated on the actual type of the value. If the dispatcher
is able to consume the value of the requested type, it must return the
pointer to the appropriate visitor interface. Otherwise it returns NULL
. When (and if) the corresponding
visitor is acquired, the attribute value object only has to pass the contained
value to the visitor.
Happily, there is no need to write type dispatchers from scratch. The library
provides two kinds of type dispatchers that implement the type_dispatcher
and type_visitor
interfaces and encapsulate the visitor lookup.
#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
Static type dispatchers are used when the set of types that needs to be
supported for extraction is known at compile time. The static_type_dispatcher
class template is parametrized with an MPL type sequence of types that
need to be supported. The dispatcher inherits from type_dispatcher
and type_visitor
instances
for all types in the MPL sequence. All you need to do is derive your class
from the dispatcher and implement the visit
methods for all supported types, like this:
// A simple attribute value template< typename T > struct my_value : public logging::attribute_value { T m_Value; explicit my_value(T const& value) : m_Value(value) {} // The function passes the contained type into the dispatcher bool dispatch(logging::type_dispatcher& dispatcher) { logging::type_visitor< T >* visitor = dispatcher.get_visitor< T >(); if (visitor) { visitor->visit(m_Value); return true; } else return false; } // Other functions omitted for brevity... }; // Type dispatcher for the supported types struct my_dispatcher : public logging::static_type_dispatcher< boost::mpl::vector< int, double, std::string > > { // Implement visitation logic for all supported types void visit(int const& value) { std::cout << "Received int value = " << value << std::endl; } void visit(double const& value) { std::cout << "Received double value = " << value << std::endl; } void visit(std::string const& value) { std::cout << "Received string value = " << value << std::endl; } }; int main(int, char*[]) { my_dispatcher disp; // These two attributes are supported by the dispatcher my_value< std::string > val1("Hello world!"); assert(val1.dispatch(disp)); my_value< double > val2(1.2); assert(val2.dispatch(disp)); // This one is not my_value< float > val3(-4.3); assert(!val3.dispatch(disp)); return 0; }
Tip | |
---|---|
In the example above we implemented a reduced attribute value object.
Since in most cases this implementation is always the same, the library
provides a ready-to-go attribute value in the |
The static type dispatcher also supports another way of use which allows avoidance of code duplication if values of several types have to be processed in a similar manner. In the example above we wanted to print the dispatched value on the console, whatever it is. The same can be achieved with templated metafunction class which is injected into the dispatcher as a visitor.
// The templated visitor will be instantiated on every type supported by the dispatcher template< typename T > struct my_visitor : public logging::type_visitor< T > { void visit(T const& value) { std::cout << "Received " << typeid(T).name() << " value = " << value << std::endl; } }; // Type dispatcher for the supported types typedef logging::static_type_dispatcher< boost::mpl::vector< int, double, std::string >, boost::mpl::quote1< my_visitor > > my_dispatcher;
This dispatcher can be used in precisely the same way as the previously defined one. Note also that Boost.MPL lambda expressions are supported as visitor generators.
Tip | |
---|---|
See also attribute value extractors for an even simpler solution if all you want is to get an attribute value. |
#include <boost/log/utility/type_dispatch/dynamic_type_dispatcher.hpp>
If the set of types that have to be supported is not available at compile
time, the dynamic_type_dispatcher
class is there to help. One can use its register_type
method to add support for a particular type. The user has to pass a function
object along with the type, this functor will be called when a visitor
for the specified type is invoked. Considering the my_value
from the code sample for static type dispatcher is intact, the code can
be rewritten as follows:
// Implement visitation logic for all supported types void on_int(int const& value) { std::cout << "Received int value = " << value << std::endl; } void on_double(double const& value) { std::cout << "Received double value = " << value << std::endl; } void on_string(std::string const& value) { std::cout << "Received string value = " << value << std::endl; } int main(int, char*[]) { logging::dynamic_type_dispatcher disp; // Register type visitors disp.register_type< int >(&on_int); disp.register_type< double >(&on_double); disp.register_type< std::string >(&on_string); // These two attributes are supported by the dispatcher my_value< std::string > val1("Hello world!"); assert(val1.dispatch(disp)); my_value< double > val2(1.2); assert(val2.dispatch(disp)); // This one is not my_value< float > val3(-4.3); assert(!val3.dispatch(disp)); return 0; }
Of course, complex function objects, like those provided by Boost.Bind, are also supported.
#include <boost/log/utility/type_dispatch/standard_types.hpp> #include <boost/log/utility/type_dispatch/date_time_types.hpp>
One may notice that when using type dispatchers and defining filters and formatters it may be convenient to have some predefined type sequences to designate frequently used sets of types. The library provides several such sets.
Table 1.3. Standard types (standard_types.hpp)
Type sequence |
Meaning |
---|---|
|
All integral types, including |
|
Floating point types |
|
Includes |
|
Narrow or wide string types. Currently only includes STL string types and string literals. |
There are also a number of time-related type sequences available:
Table 1.4. Time-related types (date_time_types.hpp)
Type sequence |
Meaning |
---|---|
|
All types defined in C/C++ standard that have both date and time portions |
|
All types defined in Boost.DateTime that have both date and time portions |
|
Includes |
|
All types defined in C/C++ standard that have date portion. Currently
equivalent to |
|
All types defined in Boost.DateTime that have date portion |
|
Includes |
|
All types defined in C/C++ standard that have time portion. Currently
equivalent to |
|
All types defined in Boost.DateTime
that have time portion. Currently equivalent to |
|
Includes |
|
All types defined in C/C++ standard that are used to represent
time duration. Currently only includes |
|
All time duration types defined in Boost.DateTime |
|
Includes |
|
All time period types defined in Boost.DateTime |
|
Currently equivalent to |
#include <boost/log/utility/attribute_value_extractor.hpp>
Attribute value extractors serve as a helper tool on top of type
dispatchers in order to simplify extracting attribute values in
generic code. The functionality is implemented in the attribute_value_extractor
class template, parametrized on character type and type or MPL sequence
of types that have to be supported for dispatch. The attribute_value_extractor
instance is a binary function object that accepts a set of attribute values
and another function object that will receive the extracted attribute value.
The name of the attribute to be extracted is given as the constructor argument
to the extractor. The key advantage of using extractors instead of raw
dispatchers is that the receiving function object can have a template
operator ()
.
Obviously, this allows reducing the amount of code when similar processing
is needed for attributes of different types. For example:
// A generic function object that outputs attribute value struct print_attribute_value { typedef void result_type; // This operator will be instantiated for all possible types of the attribute value template< typename T > void operator() (T const& value) const { std::cout << "Received " << logging::type_info_wrapper(typeid(T)).pretty_name() << " attribute value: " << value << std::endl; } }; void foo(attribute_values_view const& attrs) { // Let's assume we want to output the value of the // attribute "MyAttr" that may have any numeric type logging::attribute_value_extractor< char, logging::numeric_types > extractor1("MyAttr"); assert(extractor1(attrs, print_attribute_value())); // The extractor returns false if it is unable to extract the value logging::attribute_value_extractor< char, std::complex< double > > extractor2("MyAttr"); assert(!extractor2(attrs, print_attribute_value())); }
Note that the predefined type sequences provided by the library can be used freely with extractors just as well as with filters and formatters. Also note that specifying a single type of the attribute value instead of type sequence is also perfectly valid.
The library also provides an extract
convenience function that automatically creates extractor object. The
foo
function from the example
above can be rewritten like this:
void foo(attribute_values_view const& attrs) { assert(extract< logging::numeric_types >("MyAttr", attrs, print_attribute_value())); assert(!extract< std::complex< double > >("MyAttr", attrs, print_attribute_value())); }
#include <boost/log/utility/record_ordering.hpp>
There are cases when log records need to be ordered. One possible use case is storing records in a container or a priority queue. The library provides two types of record ordering predicates out of the box:
The handle_ordering
class
allows application of a quick opaque ordering. The result of this ordering
is not stable between different runs of the application, however it provides
the best performance. The handle_ordering
is a template that is specialized with an optional predicate function that
will be able to compare void*
pointers. By default a std::less
equivalent is used.
// A set of unique records std::set< logging::record, logging::handle_ordering< > > m_Records;
This kind of ordering is implemented with the attribute_value_ordering
class and is based on the attribute values attached to the record. The
predicate will seek for an attribute value with the specified name in both
records being ordered and attempt to compare the attribute values.
// Ordering type definition typedef logging::attribute_value_ordering< char, // character type that is used by Boost.Log int // attribute value type > ordering; // Records organized into a queue based on the "Severity" attribute value std::priority_queue< logging::record, std::vector< logging::record >, ordering > m_Records(ordering("Severity"));
Like the handle_ordering
,
attribute_value_ordering
also accepts the third optional template parameter, which should be the
predicate to compare attribute values (int
s
in the example above). By default, a std::less
equivalent is used.
You can also use the make_attr_ordering
generator function to automatically generate the attribute_value_ordering
instance based on the attribute value name and the ordering function. This
might be useful if the ordering function has a non-trivial type, like the
ones Boost.Bind
provides.
#include <boost/log/utility/exception_handler.hpp>
The library provides exception handling hooks in different places. Tools, defined in this header, provide an easy way of implementing function objects suitable for such hooks.
An exception handler is a function object that accepts no arguments. The
result of the exception handler is ignored and thus should generally be
void
. Exception handlers are
called from within catch
sections
by the library, therefore in order to reacquire the exception object it
has to rethrow it. The header defines an exception_handler
template functor that does just that and then forwards the exception object
to an unary user-defined functional object. The make_exception_handler
function can be used to simplify the handler construction. All expected
exception types should be specified explicitly in the call, in the order
they would appear in the catch
sections (i.e. from most specific ones to the most general ones).
struct my_handler { typedef void result_type; void operator() (std::runtime_error const& e) const { std::cout << "std::runtime_error: " << e.what() << std::endl; } void operator() (std::logic_error const& e) const { std::cout << "std::logic_error: " << e.what() << std::endl; throw; } }; void init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // Setup a global exception handler that will call my_handler::operator() // for the specified exception types core->set_exception_handler(logging::make_exception_handler< std::runtime_error, std::logic_error >(my_handler())); }
As you can see, you can either suppress the exception by returning normally
from operator()
in the user-defined handler functor, or rethrow the exception, in which
case it will propagate further. If it appears that the exception handler
is invoked for an exception type that cannot be caught by any of the specified
types, the exception will be propagated without any processing. In order
to catch such situations, there exists the nothrow_exception_handler
class. It invokes the user-defined functor with no arguments if it cannot
determine the exception type.
struct my_handler { typedef void result_type; void operator() (std::runtime_error const& e) const { std::cout << "std::runtime_error: " << e.what() << std::endl; } void operator() (std::logic_error const& e) const { std::cout << "std::logic_error: " << e.what() << std::endl; throw; } void operator() () const { std::cout << "unknown exception" << std::endl; } }; void init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // Setup a global exception handler that will call my_handler::operator() // for the specified exception types. Note the std::nothrow argument that // specifies that all other exceptions should also be passed to the functor. core->set_exception_handler(logging::make_exception_handler< std::runtime_error, std::logic_error >(my_handler(), std::nothrow)); }
It is sometimes convenient to completely suppress all exceptions at a certain
library level. The make_exception_suppressor
function creates an exception handler that simply does nothing upon exception
being caught. For example, this way we can disable all exceptions from
the logging library:
void init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // Disable all exceptions core->set_exception_handler(logging::make_exception_suppressor()); }
This part of the library is provided in order to simplify logging initialization and provide basic tools to develop user-specific initialization mechanisms. It is known that setup capabilities and preferences may vary widely from application to application, therefore the library does not attempt to provide a universal solution for this task. The provided tools are mostly intended to serve as a quick drop-in support for logging setup and a set of instruments to implement something more elaborate and more fitting users' needs.
Some of the features described in this section will require the separate library binary, with name based on "boost_log_setup" substring. This binary depends on the main library binary.
#include <boost/log/utility/init/to_console.hpp> #include <boost/log/utility/init/to_file.hpp> #include <boost/log/utility/init/common_attributes.hpp>
The library provides a number of functions that simplify some common initialization procedures, like sink and commonly used attributes registration. This is not much functionality. However, it saves a couple of minutes of learning the library for a newcomer.
Logging to the application console is the simplest way to see the logging library in action. To achieve this, one can initialize the library with a single function call, like this:
int main(int, char*[]) { // Initialize logging to std::clog logging::init_log_to_console(); // Here we go, we can write logs right away src::logger lg; BOOST_LOG(lg) << "Hello world!"; return 0; }
Pretty easy, isn't it? There is winit_log_to_console
function for wide-character logging. If you want to put logs to some
other standard stream, you can pass the stream to the init_log_to_console
function as an argument. E.g. enabling logging to std::cout
instead of std::clog
would look like this:
logging::init_log_to_console(std::cout);
What's important, is that you can further manage the console sink if
you save the shared_ptr
to the sink that this function returns. This allows you to set up things
like filter, formatter and auto-flush flag.
int main(int, char*[]) { // Initialize logging to std::clog boost::shared_ptr< sinks::synchronous_sink< sinks::text_ostream_backend > > sink = logging::init_log_to_console(); sink->set_filter(flt::attr< int >("Severity") >= 3); sink->locked_backend()->auto_flush(true); // Here we go, we can write logs right away src::logger lg; BOOST_LOG(lg) << "Hello world!"; return 0; }
Similarly to console, one can use a single function call to enable logging to a file. All you have to do is to provide the file name:
int main(int, char*[]) { // Initialize logging to the "test.log" file logging::init_log_to_file("test.log"); // Here we go, we can write logs right away src::logger lg; BOOST_LOG(lg) << "Hello world!"; return 0; }
Like with init_log_to_console
,
the init_log_to_file
function has its wide-character counterpart winit_log_to_file
and returns the shared_ptr
to the registered sink. The functions do not conflict and may be combined
freely, so it is possible to set up logging to the console and a couple
of files, including filtering and formatting, in about 10 lines of code.
Lastly, there is an add_common_attributes
function that registers two frequently used attributes: "LineID"
and "TimeStamp". The former counts log record being made and
has attribute value unsigned int
. The latter, as its name implies,
provides the current time for each log record, in the form of boost::posix_time::ptime
(see Boost.DateTime).
These two attributes are registered globally, so they will remain available
in all threads and loggers. This makes the final version of our code
sample look something like this:
int main(int, char*[]) { // Initialize sinks logging::init_log_to_console()->set_filter(flt::attr< int >("Severity") >= 4); boost::function< void (std::ostream&, logging::record const&) > formatter = fmt::stream << fmt::attr< unsigned int >("LineID", "[% 9u] ") << fmt::date_time< boost::posix_time::ptime >("TimeStamp") << " *" << fmt::attr< int >("Severity") << "* " << fmt::message(); logging::init_log_to_file("complete.log")->locked_backend()->set_formatter(formatter); boost::shared_ptr< sinks::synchronous_sink< sinks::text_ostream_backend > > sink = logging::init_log_to_file("essential.log"); sink->locked_backend()->set_formatter(formatter); sink->set_filter(flt::attr< int >("Severity") >= 1); // Register common attributes logging::add_common_attributes(); // Here we go, we can write logs src::logger lg; BOOST_LOG(lg) << "Hello world!"; return 0; }
#include <boost/log/utility/init/filter_parser.hpp> #include <boost/log/utility/init/formatter_parser.hpp>
Filter and formatter parsers allow constructing filters and formatters
from a descriptive string. The function parse_filter
is responsible for recognizing filters and parse_formatter
- for recognizing formatters.
In the case of filters the string is formed of a sequence of condition expressions, interconnected with boolean operations. There are two operations supported: conjunction (designated as "&" or "and") and disjunction ("|" or "or"). Each condition itself may be either a single condition or a sub-filter, taken in round brackets. Each condition can be negated with the "!" sign or "not" keyword. The condition, if it's not a sub-filter, usually consists of an attribute name enclosed in percent characters ("%"), a relation keyword and an operand. The relation and operand may be omitted, in which case the condition is assumed to be the requirement of the attribute presence (with any type).
filter: condition { op condition } op: & and | or condition: !condition not condition (filter) %attribute_name% %attribute_name% relation operand relation: > < = != >= <= begins_with ends_with contains matches
Below are some examples of filters:
Table 1.5. Examples of filters
Filter string |
Description |
---|---|
|
The filter returns |
|
The filter returns |
!( |
The filter returns |
|
The filter returns |
The formatter string syntax is even simpler and pretty much resembles
Boost.Format
format string syntax. The string must contain attribute names enclosed
in percent signs ("%"), the corresponding attribute value will
replace these placeholders. The placeholder "%_%" is special,
it will be replaced with the log record text. For instance, [%TimeStamp%] *%Severity%*
%_%
formatter string will make log records
look like this: [2008-07-05 13:44:23] *0* Hello world
.
It must be noted, though, that by default the library only supports those attribute value types which are known at the library build time. User-defined types will not work properly in parsed filters and formatters until registered in the library. More on this is available in the Extending the library section.
Note | |
---|---|
The parsed formatters and filters are generally less optimal than the equivalent ones written in code. This is because of two reasons: (*) the programmer usually knows more about types of the attribute values that may be involved in formatting or filtering and (*) the compiler has a better chance to optimize the formatter or filter if it is known in compile time. Therefore, if the performance matters, it is advised to avoid parsed filters and formatters. |
#include <boost/log/utility/init/from_settings.hpp>
The header defines components for library initialization from settings
container. The settings container is basically a set of named parameters
divided into sections. The container is implemented with the basic_settings
class template. There
are several constraints on how parameters are stored in the container:
So basically, settings container is a two-layer associative container,
with two string keys. The parameter values are stored as Boost.Any
values. Each parameter supported by the library must have the according
type within the any
variant
value. The supported parameters, their types and meaning is described
below.
Tip | |
---|---|
In the tables below, the |
Table 1.6. Section "Core". Logging core settings.
Parameter |
Type |
Description |
---|---|---|
Filter |
|
Global filter to be installed to the core. If specified in string form, it should conform to the rules described here. If not specified, the global filter is not set. |
DisableLogging |
|
If |
Sink settings are divided into separate sections - one section for each sink. The section names should begin with the "Sink:" prefix, while the rest of the section name should denote a user-defined sink name. For example, "Sink:MyFile".
Table 1.7. Sections with names beginning with "Sink:". Common sink settings.
Parameter |
Type |
Description |
---|---|---|
Destination |
|
Sink backend type. Mandatory parameter. May have one of these
values: Console,
TextFile,
Syslog.
On Windows the following values are additionally supported:
SimpleEventLog,
Debugger.
Also, user-defined sink names may also be supported if registered
by calling |
Filter |
|
Sink-specific filter. If specified in string form, it should conform to the rules described here. If not specified, the filter is not set. |
Asynchronous |
|
If |
Besides the common settings that all sinks support, some sink backends also accept a number of specific parameters. These parameters should be specified in the same section.
Table 1.8. "Console" sink settings
Parameter |
Type |
Description |
---|---|---|
Formatter |
|
Log record formatter to be used by the sink. If specified in string form, it should conform to the rules described here. If not specified, the default formatter is used. |
AutoFlush |
|
Enables or disables the auto-flush feature of the backend.
If not specified, the default value |
Table 1.9. "TextFile" sink settings
Parameter |
Type |
Description |
---|---|---|
FileName |
|
The file name pattern for the sink backend. This parameter is mandatory. |
Formatter |
|
Log record formatter to be used by the sink. If specified in string form, it should conform to the rules described here. If not specified, the default formatter is used. |
AutoFlush |
|
Enables or disables the auto-flush feature of the backend.
If not specified, the default value |
RotationSize |
Any fundamental integer type |
File size, in bytes, upon which file rotation will be performed. If not specified, no size-based rotation will be made. |
RotationInterval |
Any fundamental integer type |
Time interval, in seconds, upon which file rotation will be performed. See also the RotationTimePoint parameter and the note below. |
RotationTimePoint |
|
Time point or a predicate that detects at what moment of time to perform log file rotation. See also the RotationInterval parameter and the note below. |
Target |
|
Target directory name, in which the rotated files will be stored. If this parameter is specified, rotated file collection is enabled. Otherwise the feature is not enabled, and all corresponding parameters are ignored. |
MaxSize |
Any fundamental integer type |
Total size of files in the target directory, in bytes, upon which the oldest file will be deleted. If not specified, no size-based file cleanup will be performed. |
MinFreeSpace |
Any fundamental integer type |
Minimum free space in the target directory, in bytes, upon which the oldest file will be deleted. If not specified, no space-based file cleanup will be performed. |
ScanForFiles |
|
Mode of scanning for old files in the target directory. If specified in string form, the following values are permitted: "All", "Matching". If not specified, no scanning will be performed. |
The time-based rotation can be set up with one of the two parameters: RotationInterval or RotationTimePoint. Not more than one of these parameters should be specified for a given sink. If none is specified, no time-based rotation will be performed.
The RotationTimePoint can be specified in two forms: a predicate or a
string. The predicate form is convenient if the settings container is
filled by the user's code. In this case, the predicate should take no
arguments and return bool
,
which is true
when the file
rotation should take place. A good example of such predicate is the
rotation_at_time_point
class, which is described in this
section.
If the parameter is supplied in the string form, it should have one of the following formats, according to the Boost.DateTime format notation:
In case if the settings are loaded from a settings file, the string form is the only way to set up the file rotation at a certain time point.
Table 1.10. "Syslog" sink settings
Parameter |
Type |
Description |
---|---|---|
LocalAddress |
|
Local address to initiate connection to the syslog server. If not specified, the default local address will be used. |
TargetAddress |
|
Remote address of the syslog server. If not specified, the local address will be used. |
Table 1.11. "SimpleEventLog" sink settings
Parameter |
Type |
Description |
---|---|---|
LogName |
|
Log name to write events into. If not specified, the default log name will be used. |
LogSource |
|
Log source to write events from. If not specified, the default source will be used. |
Registration |
|
Mode of log source registration in Windows registry. If specified in string form, the following values are supported: "Never", "OnDemand", "Forced". If not specified, on-demand registration will be performed. |
The user is free to fill the settings container from whatever settings source he needs. The usage example is below:
void init_logging() { logging::settings setts; setts["Core"]["Filter"] = "%Severity% >= warning"; setts["Core"]["DisableLogging"] = false; setts["Sink:Console"]["Destination"] = "Console"; setts["Sink:Console"]["Filter"] = "%Severity% >= fatal"; setts["Sink:Console"]["AutoFlush"] = true; setts["Sink:File"]["Destination"] = "TextFile"; setts["Sink:File"]["FileName"] = "MyApp_%3N.log"; setts["Sink:File"]["AutoFlush"] = true; setts["Sink:File"]["RotationSize"] = 10 * 1024 * 1024; // 10 MiB logging::init_from_settings(setts); }
The settings reader also allows to be extended to support custom sink types. See the Extending the library section for more information.
#include <boost/log/utility/init/from_stream.hpp>
Support for configuration files is a frequently requested feature of
the library. And despite the fact there is no ultimately convenient and
flexible format of the library settings, the library provides preliminary
support for this feature. The functionality is implemented with a simple
function init_from_stream
,
which accepts an STL input stream and reads the library settings from
it. The function then passes on the read settings to the init_from_settings
function, described
above. Therefore
the parameter names and their meaning is the same as for the init_from_settings
function.
The settings format is quite simple and widely used. Below is the description of syntax and parameters.
# Comments are allowed. Comment line begins with the '#' character # and spans until the end of the line. # Logging core settings section. May be omitted if no parameters specified within it. [Core] DisableLogging=false Filter="%Severity% > 3" # Sink settings sections [Sink:MySink1] # Sink destination type Destination=Console # Sink-specific filter. Optional, by default no filter is applied. Filter="%Target% contains "MySink1"" # Formatter string. Optional, by default only log record message text is written. Format="<%TimeStamp%> - %_%" # The flag shows whether the sink should be asynchronous Asynchronous=false # Enables automatic stream flush after each log record. AutoFlush=true
Here's the usage example:
int main(int, char*[]) { // Read logging settings from a file std::ifstream file("settings.ini"); logging::init_from_stream(file); return 0; }