Quick Links: |
Provide macros and utility functions to facilitate logging. More...
Namespaces | |
namespace | ball |
ball::Log | namespace for logging utilities (for internal use only) |
BALL_LOG_SET_CATEGORY(C) | set a category for logging to the specified C |
BALL_LOG_SET_DYNAMIC_CATEGORY(C) | set a run-time-dependent category |
BALL_LOG_SET_CLASS_CATEGORY(C) | set a category in the scope of a class |
BALL_LOG_SET_NAMESPACE_CATEGORY(C) | set a category in a namespace |
BALL_LOG_SET_CATEGORY_HIERARCHICALLY(C) | set a category hierarchically |
BALL_LOG_SET_DYNAMIC_CATEGORY_HIERARCHICALLY(C) | set a run-time category |
BALL_LOG_SET_CLASS_CATEGORY_HIERARCHICALLY(C) | set a class category |
BALL_LOG_SET_NAMESPACE_CATEGORY_HIERARCHICALLY(C) | set a namespace category |
BALL_LOG_TRACE | produce a log record with the e_TRACE severity level |
BALL_LOG_DEBUG | produce a log record with the e_DEBUG severity level |
BALL_LOG_INFO | produce a log record with the e_INFO severity level |
BALL_LOG_WARN | produce a log record with the e_WARN severity level |
BALL_LOG_ERROR | produce a log record with the e_ERROR severity level |
BALL_LOG_FATAL | produce a log record with the e_FATAL severity level |
BALL_LOG_STREAM(SEV) | produce a log record with the specified SEV level |
BALL_LOGCB_TRACE(CB) | produce a e_TRACE log record using callback CB |
BALL_LOGCB_DEBUG(CB) | produce a e_DEBUG log record using callback CB |
BALL_LOGCB_INFO(CB) | produce an e_INFO log record using callback CB |
BALL_LOGCB_WARN(CB) | produce a e_WARN log record using callback CB |
BALL_LOGCB_ERROR(CB) | produce an e_ERROR log record using callback CB |
BALL_LOGCB_FATAL(CB) | produce a e_FATAL log record using callback CB |
BALL_LOGCB_STREAM(SEV, CB) | produce a SEV log record using callback |
BALL_LOGVA_TRACE(MSG, ...) | produce e_TRACE record using printf format |
BALL_LOGVA_DEBUG(MSG, ...) | produce e_DEBUG record using printf format |
BALL_LOGVA_INFO( MSG, ...) | produce e_INFO record using printf format |
BALL_LOGVA_WARN( MSG, ...) | produce e_WARN record using printf format |
BALL_LOGVA_ERROR(MSG, ...) | produce e_ERROR record using printf format |
BALL_LOGVA_FATAL(MSG, ...) | produce e_FATAL record using printf format |
BALL_LOGVA(SEV, MSG, ...) | produce a SEV log record using printf format |
BALL_LOG_TRACE_BLOCK | set code block with e_TRACE condition of execution |
BALL_LOG_DEBUG_BLOCK | set code block with e_DEBUG condition of execution |
BALL_LOG_INFO_BLOCK | set a code block with e_INFO condition of execution |
BALL_LOG_WARN_BLOCK | set a code block with e_WARN condition of execution |
BALL_LOG_ERROR_BLOCK | set code block with e_ERROR condition of execution |
BALL_LOG_FATAL_BLOCK | set code block with e_FATAL condition of execution |
BALL_LOG_STREAM_BLOCK(SEV) | set a code block with SEV condition |
BALL_LOGCB_TRACE_BLOCK(CB) | set e_TRACE block with the specified callback |
BALL_LOGCB_DEBUG_BLOCK(CB) | set e_DEBUG block with the specified callback |
BALL_LOGCB_INFO_BLOCK(CB) | set e_INFO block with the specified callback |
BALL_LOGCB_WARN_BLOCK(CB) | set e_WARN block with the specified callback |
BALL_LOGCB_ERROR_BLOCK(CB) | set an e_ERROR block with the specified CB |
BALL_LOGCB_FATAL_BLOCK(CB) | set e_FATAL block with the specified callback |
BALL_LOGCB_STREAM_BLOCK(SEV, CB) | set a SEV block with the specified CB |
BALL_LOG_IS_ENABLED(SEV) | indicate if SEV is severe enough for logging |
ball_loggermanager
component. In particular, the macros defined herein greatly simplify the mechanics of generating log records. The utility functions provided in ball::Log
are intended only for use by the macros and should not be called directly. ball::LoggerManager
. In particular, the macros do not have any effect unless the logger manager singleton is initialized. Note that the flow of control may pass through a use of any of the macros before the logger manager singleton has been initialized or after it has been destroyed; however, control should not pass through any macro use during logger manager singleton initialization or destruction. See ball_loggermanager
|Logger Manager Singleton Initialization for details on the recommended procedure for initializing the singleton. printf
-style logging macros (described further below). BALL_LOG_SET_CATEGORY(CATEGORY)
: CATEGORY
(assumed to be of type convertible to const char *
). On the first invocation of this macro in a code block, the ball::Log::setCategory
method is invoked to retrieve the address of an appropriate category structure for its scope; subsequent invocations will use a cached address of the category. (See the function-level documentation of ball::Log::setCategory
for more information.) This macro must be used at block scope, and can be used at most once in any given block (or else a compiler diagnostic will result).BALL_LOG_SET_DYNAMIC_CATEGORY(CATEGORY)
: CATEGORY
(assumed to be of type convertible to const char *
). On EVERY invocation of this macro in a code block, the ball::Log::setCategory
method is invoked to retrieve the address of an appropriate category structure for its scope; the address returned from ball::Log::setCategory
is NOT cached for subsequent calls. (See the function-level documentation of ball::Log::setCategory
for more information.) This macro must be used at block scope and can be used at most once in any given block (or else a compiler diagnostic will result). Note that this macro should be used to create categories that depend on RUN-TIME values only (e.g., LUW or UUID).BALL_LOG_SET_CATEGORY
or BALL_LOG_SET_DYNAMIC_CATEGORY
in any given block (or else a compiler diagnostic will result). Note that categories that are set using these macros, including dynamic categories, are not destroyed until the logger manager singleton is destroyed. BALL_LOG_SET_CLASS_CATEGORY(CATEGORY)
: CATEGORY
(assumed to be of type convertible to const char *
) in the scope of the class within which this macro is used. Similar to BALL_LOG_SET_CATEGORY
, the category is set once only, the first time that it is accessed (i.e., it is not a dynamic category). This macro must be used, at most once, within the definition of a class or class template (or else a compiler diagnostic will result). Note that use of this macro may occur in either a public
, private
, or protected
section of a class's interface, although private
should be preferred.BALL_LOG_SET_CATEGORY
and BALL_LOG_SET_DYNAMIC_CATEGORY
), class-scope categories are not destroyed until the logger manager singleton is destroyed. BALL_LOG_SET_NAMESPACE_CATEGORY(CATEGORY)
: CATEGORY
(assumed to be of type convertible to const char *
) in the namespace (or global) scope within which this macro is used. Similar to BALL_LOG_SET_CATEGORY
, the category is set once only, the first time that it is accessed (i.e., it is not a dynamic category). This macro may be used, in .cpp
files only, at most once in any given namespace and at most once at global scope (or else a compiler diagnostic will result). Do NOT use this macro in .h
files.BALL_LOG_SET_CATEGORY
and BALL_LOG_SET_DYNAMIC_CATEGORY
), namespace-scope categories are not destroyed until the logger manager singleton is destroyed. BALL_LOG_SET_CATEGORY_HIERARCHICALLY(CATEGORY)
Set a category for logging to the specified CATEGORY
(assumed to be of type convertible to const char *
). On the first invocation of this macro in a code block, the ball::Log::setCategoryHierarchically
method is invoked to retrieve the address of an appropriate category structure for its scope; subsequent invocations will use a cached address of the category. (See the function-level documentation of ball::Log::setCategoryHierarchically
for more information.) This macro must be used at block scope, and can be used at most once in any given block (or else a compiler diagnostic will result).BALL_LOG_SET_DYNAMIC_CATEGORY_HIERARCHICALLY(CATEGORY)
: CATEGORY
(assumed to be of type convertible to const char *
). On EVERY invocation of this macro in a code block, the ball::Log::setCategoryHierarchically
method is invoked to retrieve the address of an appropriate category structure for its scope; the address returned from ball::Log::setCategoryHierarchically
is NOT cached for subsequent calls. (See the function-level documentation of ball::Log::setCategoryHierarchically
for more information.) This macro must be used at block scope and can be used at most once in any given block (or else a compiler diagnostic will result). Note that this macro should be used to create categories that depend on RUN-TIME values only (e.g., LUW or UUID).BALL_LOG_SET_CLASS_CATEGORY_HIERARCHICALLY(CATEGORY)
Set a category for logging to the specified CATEGORY
(assumed to be of type convertible to const char *
) in the scope of the class within which this macro is used. Similar to BALL_LOG_SET_CATEGORY_HIERARCHICALLY
, the category is set once only, using the ball::Log::setCategoryHierarchically
function, the first time that it is accessed (i.e., it is not a dynamic category). (See the function-level documentation for ball::Log::setCategoryHierarchically
for more information.) This macro must be used, at most once, within the definition of a class or class template (or else a compiler diagnostic will result). Note that use of this macro may occur in either a public
, private
, or protected
section of a class's interface, although private
should be preferred.BALL_LOG_SET_NAMESPACE_CATEGORY_HIERARCHICALLY(CATEGORY)
Set a category for logging to the specified CATEGORY
(assumed to be of type convertible to const char *
) in the namespace (or global) scope within which this macro is used. Similar to BALL_LOG_SET_CATEGORY_HIERARCHICALLY
, the category is set once only, using the ball::Log::setCategoryHierarchically
function, the first time that it is accessed (i.e., it is not a dynamic category). (See the function-level documentation for ball::Log::setCategoryHierarchically
for more information.) This macro may be used, in .cpp
files only, at most once in any given namespace and at most once at global scope (or else a compiler diagnostic will result). Do NOT use this macro in .h
files.__FILE__
macro. ball
logging subsystem: BALL_LOG_INFO << ++i; // (!) May or may not be incremented BALL_LOG_TRACE_BLOCK { processRequest(...); // (!) May or may not be called }
BALL_LOG_TRACE
, BALL_LOG_DEBUG
, BALL_LOG_INFO
, BALL_LOG_WARN
, BALL_LOG_ERROR
, and BALL_LOG_FATAL
, are the ones most commonly used for logging. They have the following usage pattern: BALL_LOG_TRACE << X << Y ... ; BALL_LOG_DEBUG << X << Y ... ; BALL_LOG_INFO << X << Y ... ; BALL_LOG_WARN << X << Y ... ; BALL_LOG_ERROR << X << Y ... ; BALL_LOG_FATAL << X << Y ... ; where X, Y, ... represents any sequence of values for which 'operator<<' is defined. The resulting formatted message string is logged with the severity indicated by the name of the macro (e.g., 'BALL_LOG_TRACE' logs with severity 'ball::Severity::e_TRACE').
BALL_LOG_STREAM
, requires that the severity be explicitly supplied as an argument: BALL_LOG_STREAM(SEVERITY) << X << Y ... ; where X, Y, ... represents any sequence of values for which 'operator<<' is defined. The resulting formatted message string is logged with the specified 'SEVERITY'.
BALL_LOG_TRACE
, etc., allow the caller to specify a "callback" function that is passed the ball::UserFields *
used to represent the user fields of a log record. BALL_LOGCB_TRACE
, BALL_LOGCB_DEBUG
, BALL_LOGCB_INFO
, BALL_LOGCB_WARN
, BALL_LOGCB_ERROR
, and BALL_LOGCB_FATAL
have the following usage pattern: BALL_LOGCB_TRACE(CALLBACK) << X << Y ... ; BALL_LOGCB_DEBUG(CALLBACK) << X << Y ... ; BALL_LOGCB_INFO(CALLBACK) << X << Y ... ; BALL_LOGCB_WARN(CALLBACK) << X << Y ... ; BALL_LOGCB_ERROR(CALLBACK) << X << Y ... ; BALL_LOGCB_FATAL(CALLBACK) << X << Y ... ; where X, Y, ... represents any sequence of values for which 'operator<<' is defined and 'CALLBACK' is a callback taking a 'ball::UserFields *' as an argument. The resulting formatted message string is logged with the severity indicated by the name of the macro (e.g., 'BALL_LOGCB_ERROR' logs with severity 'ball::Severity::e_ERROR'). The generated log record will contain the 'ball::UserFields' representing user fields as populated by 'CALLBACK'. Note that the callback supplied to the logging macro must match the prototype 'void (*)(ball::UserFields *)'.
BALL_LOGCB_STREAM
, requires that the severity be explicitly supplied as an argument: BALL_LOGCB_STREAM(SEVERITY, CALLBACK) << X << Y ... ; where X, Y, ... represents any sequence of values for which 'operator<<' is defined. The resulting formatted message string is logged with the specified 'SEVERITY'. The generated log record will contain the 'ball::UserFields' representing user fields as populated by 'CALLBACK'. Note that the callback supplied to the logging macro must match the prototype 'void (*)(ball::UserFields *)'.
printf
-style format specifications: BALL_LOGVA_TRACE(MSG, ...); BALL_LOGVA_DEBUG(MSG, ...); BALL_LOGVA_INFO( MSG, ...); BALL_LOGVA_WARN( MSG, ...); BALL_LOGVA_ERROR(MSG, ...); BALL_LOGVA_FATAL(MSG, ...); Format the specified '...' optional arguments, if any, according to the 'printf'-style format specification in the specified 'MSG' (assumed to be of type convertible to 'const char *') and log the resulting formatted message string with the severity indicated by the name of the macro (e.g., 'BALL_LOGVA_INFO' logs with severity 'ball::Severity::e_INFO'). The behavior is undefined unless the number and types of optional arguments are compatible with the format specification in 'MSG'. Note that each use of these macros must be terminated by a ';'.
printf
-style macro, BALL_LOGVA
, requires that the severity be explicitly supplied as an argument: BALL_LOGVA(SEVERITY, MSG, ...); Format the specified '...' optional arguments, if any, according to the 'printf'-style format specification in the specified 'MSG' (assumed to be of type convertible to 'const char *') and log the resulting formatted message string with the specified 'SEVERITY'. The behavior is undefined unless the number and types of optional arguments are compatible with the format specification in 'MSG'. Note that each use of this macro must be terminated by a ';'.
BALL_LOG_TRACE_BLOCK { ... } BALL_LOG_DEBUG_BLOCK { ... } BALL_LOG_INFO_BLOCK { ... } BALL_LOG_WARN_BLOCK { ... } BALL_LOG_ERROR_BLOCK { ... } BALL_LOG_FATAL_BLOCK { ... }
BALL_LOG_STREAM_BLOCK
, requires that the severity be explicitly supplied as an argument: BALL_LOG_STREAM_BLOCK(SEVERITY) { ... }
BALL_LOG_*_BLOCK
, allow the caller to specify a "callback" function that is passed the ball::UserFields *
used to represent the user fields of a log record: BALL_LOGCB_TRACE_BLOCK(CALLBACK) { ... } BALL_LOGCB_DEBUG_BLOCK(CALLBACK) { ... } BALL_LOGCB_INFO_BLOCK(CALLBACK) { ... } BALL_LOGCB_WARN_BLOCK(CALLBACK) { ... } BALL_LOGCB_ERROR_BLOCK(CALLBACK) { ... } BALL_LOGCB_FATAL_BLOCK(CALLBACK) { ... }
BALL_LOGCB_STREAM_BLOCK
, requires that the severity be explicitly supplied as an argument: BALL_LOGCB_STREAM_BLOCK(SEVERITY, CALLBACK) { ... }
BALL_LOG_OUTPUT_STREAM
, provides access to the log stream. BALL_LOG_IS_ENABLED(SEVERITY) Return 'true' if the specified 'SEVERITY' is at least as severe as any of the threshold levels of the logging category that is in scope, and 'false' otherwise.
BALL_LOG_ERROR
will not compile unless a category has been specified in the current lexical scope: BALL_LOG_SET_CATEGORY("EXAMPLE.CATEGORY");
ball::LoggerManager
singleton): BALL_LOG_FATAL << "Write this message to the log if the log threshold " << "is above 'ball::Severity::e_FATAL' (i.e., 32)."; BALL_LOG_TRACE << "Write this message to the log if the log threshold " << "is above 'ball::Severity::e_TRACE' (i.e., 192).";
bsl::vector<int> myVector(4, 328); BALL_LOG_TRACE_BLOCK { BALL_LOG_OUTPUT_STREAM << "myVector = [ "; unsigned int position = 0; for (bsl::vector<int>::const_iterator it = myVector.begin(), end = myVector.end(); it != end; ++it, ++position) { BALL_LOG_OUTPUT_STREAM << position << ':' << *it << ' '; } BALL_LOG_OUTPUT_STREAM << ']'; }
BALL_LOG_OUTPUT_STREAM
provides access to the log stream within the block. BALL_LOG_SET_CATEGORY("EQUITY.NASD")
BALL_LOG_SET_DYNAMIC_CATEGORY
) must be visible from within the lexical scope of every use of the log-generating macros. The following fragment of code shows how to set a different category in a nested inner block that hides a category set in an enclosing block: void logIt() { BALL_LOG_SET_CATEGORY("EQUITY.NASD") // Logging to category "EQUITY.NASD" unless overridden in a nested // block. // [*] ... { // [*] ... // Still logging to category "EQUITY.NASD". BALL_LOG_SET_CATEGORY("EQUITY.NASD.SUNW") // Now logging to category "EQUITY.NASD.SUNW". // [*] ... } // Again logging to category "EQUITY.NASD". // [*] ... }
logIt
, a requisite logging category is visible at each of the locations marked by [*]
. iostream
-style macros such as BALL_LOG_INFO
, allow streaming via the bsl::ostream
class
and the C++ stream operator <<
. An advantage the C++ streaming style has over the printf
style output (shown below in example 4) is that complex types often have the operator<<(ostream&, const TYPE&)
function overloaded so that they are able to be easily streamed to output. We demonstrate this here using C++ streaming to stream a bdlt::Date
to output: int lotSize = 400; const char *ticker = "SUNW"; double price = 5.65; // Trading on a market that settles 3 days in the future. bdlt::Date settle = bdlt::CurrentTime::local().date() + 3; BALL_LOG_SET_CATEGORY("EQUITY.NASD")
e_INFO
, from here on. We output a line using the BALL_LOG_INFO
macro: BALL_LOG_INFO << "[1] " << lotSize << " shares of " << ticker << " sold at " << price << " settlement date " << settle;
<ts> <pid> <tid> INFO x.cpp 1161 EQUITY.NASD [1] 400 shares of SUNW sold at 5.65 settlement date 17FEB2017
<ts>
is the timestamp, <pid>
is the process id, <tid>
is the thread id, x.cpp
is the expansion of the __FILE__
macro that is the name of the source file containing the call, 1161 is the line number of the call, and the trailing date following "settlement date" is the value of settle
. ball::Administration::addCategory
with its pass-through level set to e_INFO
and the trigger levels set at or above e_ERROR
, so a level of e_WARN
also passes through: { BALL_LOG_SET_CATEGORY("EQUITY.NASD.SUNW") // Now logging with category "EQUITY.NASD.SUNW". BALL_LOG_WARN << "[2] " << lotSize << " shares of " << ticker << " sold at " << price << " settlement date " << settle; }
<ts> <pid> <tid> WARN x.cpp 1185 EQUITY.NASD.SUNW [2] 400 shares of SUNW sold at 5.65 settlement date 17FEB2017
BALL_LOG_INFO << "[3] " << lotSize << " shares of " << ticker << " sold at " << price << " settlement date " << settle;
<ts> <pid> <tid> INFO x.cpp 1198 EQUITY.NASD [3] 400 shares of SUNW sold at 5.65 settlement date 17FEB2017
ball::Severity::e_INFO
. printf
-style macros, ensure at compile-time that no run-time format mismatches will occur. Use of the stream-based logging style exclusively will likely lead to clearer, more maintainable code with fewer initial defects. printf
-style and C++ stream-based, must occur within function scope (i.e., not at file scope). logIt
function (defined above) to log two messages using the BALL_LOGVA_INFO
logging macro provided by this component. This variadic macro takes a format string and a variable-length series of arguments, similar to printf
. int lotSize = 400; const char *ticker = "SUNW"; double price = 5.65; // Trading on a market that settles 3 days in the future. bdlt::Date settleDate = bdlt::CurrentTime::local().date() + 3;
printf
complex types like bdlt::Date
or bsl::string
, we have to convert settleDate
to a const char *
ourselves. Note that all this additional work was unnecessary in Example 3 when we used the C++ iostream
-style, rather than the printf
-style, macros. bsl::ostringstream settleOss; settleOss << settleDate; const bsl::string& settleStr = settleOss.str(); const char *settle = settleStr.c_str();
e_INFO
, and call BALL_LOGVA_INFO
to print our trade: BALL_LOG_SET_CATEGORY("EQUITY.NASD") BALL_LOGVA_INFO("[4] %d shares of %s sold at %f settlement date %s\n", lotSize, ticker, price, settle);
ball::Severity::e_INFO
: <ts> <pid> <tid> INFO x.cpp 1256 EQUITY.NASD [4] 400 shares of SUNW sold at 5.650000 settlement date 17FEB2017
<ts>
is the timestamp, <pid>
is the process id, <tid>
is the thread id, x.cpp
is the expansion of the __FILE__
macro that is the name of the source file containing the call, and 1256 is the line number of the call. BALL_LOGVA_INFO
macro is a printf
-style format specification. e_INFO
: { BALL_LOG_SET_CATEGORY("EQUITY.NASD.SUNW") // Now logging with category "EQUITY.NASD.SUNW". BALL_LOGVA_WARN("[5] %d shares of %s sold at %f settlement date %s\n", lotSize, ticker, price, settle); }
<ts> <pid> <tid> WARN x.cpp 1281 EQUITY.NASD.SUNW [5] 400 shares of SUNW sold at 5.650000 settlement date 17FEB2017
BALL_LOGVA_INFO("[6] %d shares of %s sold at %f settlement date %s\n", lotSize, ticker, price, settle);
<ts> <pid> <tid> INFO x.cpp 1294 EQUITY.NASD [6] 400 shares of SUNW sold at 5.650000 settlement date 17FEB2017
BALL_LOG_SET_DYNAMIC_CATEGORY
macro sets a category each time it is invoked (unlike BALL_LOG_SET_CATEGORY
, which sets a category only on the first invocation and uses the cached address of the category on subsequent invocations). The category name in the following processSecurity
function is a combination of a static prefix and the (dynamic) exchange
argument: void processSecurity(const char *security, const char *exchange) { bsl::string categoryName("EXCHANGE:"); categoryName.append(exchange); BALL_LOG_SET_DYNAMIC_CATEGORY(categoryName.c_str()); BALL_LOG_TRACE << "processing: " << security; // ... }
exchange
. processData
, that is passed data in a vector<char>
and information about the user who sent the data. This example function performs no actual processing, but does log a single message at the ball::Severity::e_DEBUG
threshold level. The processData
function also adds the user information passed to this function to the thread's attribute context. We will use these attributes later, to create a logging rule that enables verbose logging only for a particular user. void processData(int uuid, int luw, int terminalNumber, const bsl::vector<char>& data) // Process the specified 'data' associated with the specified Bloomberg // 'uuid', 'luw', and 'terminalNumber'. { (void)data; // suppress "unused" warning
ball::ScopedAttribute
, which adds an attribute container with one attribute to a list of containers. This is easy and efficient if the number of attributes is small, but should not be used if there are a large number of attributes. If motivated, we could use ball::DefaultAttributeContainer
, which provides an efficient container for a large number of attributes, or even create a more efficient attribute container implementation specifically for these three attributes (uuid, luw, and terminalNumber). See ball_scopedattributes
(plural) for an example of using a different attribute container, and ball_attributecontainer
for an example of creating a custom attribute container. // We use 'ball::ScopedAttribute' here because the number of // attributes is relatively small. ball::ScopedAttribute uuidAttribute("mylibrary.uuid", uuid); ball::ScopedAttribute luwAttribute("mylibrary.luw", luw); ball::ScopedAttribute termNumAttribute("mylibrary.terminalNumber", terminalNumber);
ball::Severity::e_DEBUG
level. BALL_LOG_SET_CATEGORY("EXAMPLE.CATEGORY"); BALL_LOG_DEBUG << "An example message";
ball::ScopedAttribute
(e.g., if we were using a local ball::DefaultAttributeContainer
instead), then the container **must** be removed from the ball::AttributeContext
before it is destroyed! See ball_scopedattributes
(plural) for an example. }
ball::Severity::e_TRACE
(i.e., enables verbose logging) for a particular user when calling the processData
function defined above. processData
function: This first call to processData
will not result in any logged messages because processData
logs its message at the ball::Severity::e_DEBUG
level, which is below the default configured logging threshold. ball::LoggerManagerConfiguration lmConfig; ball::LoggerManagerScopedGuard lmGuard(lmConfig); bsl::shared_ptr<ball::StreamObserver> observer = bsl::make_shared<ball::StreamObserver>(&bsl::cout); ball::LoggerManager::singleton().registerObserver(observer, "default"); BALL_LOG_SET_CATEGORY("EXAMPLE.CATEGORY"); bsl::vector<char> message; BALL_LOG_ERROR << "Processing the first message."; processData(3938908, 2, 9001, message);
ball::Severity::e_TRACE
(i.e., enabling verbose logging) if the thread's context contains an attribute with name "mylibrary.uuid" with value 3938908. Note that we use the wild-card value *
for the category so that the ball::Rule
rule will apply to all categories. ball::Rule rule("*", 0, ball::Severity::e_TRACE, 0, 0); rule.addAttribute(ball::ManagedAttribute("mylibrary.uuid", 3938908)); ball::LoggerManager::singleton().addRule(rule); BALL_LOG_ERROR << "Processing the second message."; processData(3938908, 2, 9001, message);
processData
function below, passes a uuid
of 2171395 (not 3938908) so the logging rule we defined will not apply and no message will be logged. BALL_LOG_ERROR << "Processing the third message."; processData(2171395, 2, 9001, message);
ERROR example.cpp:105 EXAMPLE.CATEGORY Processing the first message. ERROR example.cpp:117 EXAMPLE.CATEGORY Processing the second message. DEBUG example.cpp:35 EXAMPLE.CATEGORY An example message ERROR example.cpp:129 EXAMPLE.CATEGORY Processing the third message.
populateUsingPoint
that appends to the specified fields
the attributes of the point
to log: void populateUsingPoint(ball::UserFields *fields, const Point& point) // Append to the specified 'list' the name, x value, and y value of // the specified 'point'. { fields->appendString(point.name()); fields->appendInt64(point.x()); fields->appendInt64(point.y()); } int validatePoint(const Point& point) { BALL_LOG_SET_CATEGORY("EXAMPLE.CATEGORY");
populateUsingPoint
and the supplied point
to a functor object we will pass to the logging callback. Note that the callback supplied to the logging macro must match the prototype void (*)(ball::UserFields *)
. bsl::function <void(ball::UserFields *)> callback; callback = bdlf::BindUtil::bind(&populateUsingPoint, bdlf::PlaceHolders::_1, point); int numErrors = 0; if (point.x() > 255) { BALL_LOGCB_ERROR(callback) << "X > 255"; ++numErrors; } if (point.x() < -255) { BALL_LOGCB_ERROR(callback) << "X < -255"; ++numErrors; } if (point.y() > 255) { BALL_LOGCB_ERROR(callback) << "Y > 255"; ++numErrors; } if (point.y() < -255) { BALL_LOGCB_ERROR(callback) << "Y < -255"; ++numErrors; } return numErrors; }
Thing
, for which we want to do class-scope logging. The use of the BALL_LOG_SET_CLASS_CATEGORY
macro generates the requisite declarations within the definition of the class. We have used the macro in a private
section of the interface, which should be preferred, but public
(or protected
) is fine, too: // pckg_thing.h namespace pckg { class Thing { // ... private: BALL_LOG_SET_CLASS_CATEGORY("PCKG.THING"); public: // ... // MANIPULATORS void outOfLineMethodThatLogs(bool useClassCategory); // Log to the class-scope category "PCKG.THING" if the specified // 'useClassCategory' flag is 'true', and to the block-scope // category "X.Y.Z" otherwise. // ... // ACCESSORS void inlineMethodThatLogs() const; // Log a record to the class-scope category "PCKG.THING". };
inlineMethodThatLogs
method inline
within the header file and log to the class-scope category using BALL_LOG_TRACE
. Since there is no other category in scope, the record is necessarily logged to the "PCKG.THING" category that is within the scope of the Thing
class: // ... // ACCESSORS inline void Thing::inlineMethodThatLogs() const { BALL_LOG_TRACE << "log to PCKG.THING"; } } // close namespace pckg
outOfLineMethodThatLogs
method within the .cpp
file. On each invocation, this method logs one record using BALL_LOG_TRACE
. It logs to the "PCKG.THING" class-scope category if useClassCategory
is true
, and logs to the "X.Y.Z" block-scope category otherwise: // pckg_thing.cpp namespace pckg { // ... // MANIPULATORS void Thing::outOfLineMethodThatLogs(bool useClassCategory) { if (useClassCategory) { BALL_LOG_TRACE << "log to PCKG.THING"; } else { BALL_LOG_SET_CATEGORY("X.Y.Z"); BALL_LOG_TRACE << "log to X.Y.Z"; } } } // close namespace pckg
Thing
method would first log to "PCKG.THING" then log to "X.Y.Z": { BALL_LOG_TRACE << "log to PCKG.THING"; BALL_LOG_SET_CATEGORY("X.Y.Z"); BALL_LOG_TRACE << "log to X.Y.Z"; }