BDE 4.14.0 Production release
Loading...
Searching...
No Matches
ball_log.h
Go to the documentation of this file.
1/// @file ball_log.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// ball_log.h -*-C++-*-
8#ifndef INCLUDED_BALL_LOG
9#define INCLUDED_BALL_LOG
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup ball_log ball_log
15/// @brief Provide macros and utility functions to facilitate logging.
16/// @addtogroup bal
17/// @{
18/// @addtogroup ball
19/// @{
20/// @addtogroup ball_log
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#ball_log-purpose"> Purpose</a>
25/// * <a href="#ball_log-classes"> Classes </a>
26/// * <a href="#ball_log-macros"> Macros </a>
27/// * <a href="#ball_log-description"> Description </a>
28/// * <a href="#ball_log-thread-safety"> Thread Safety </a>
29/// * <a href="#ball_log-macro-reference"> Macro Reference </a>
30/// * <a href="#ball_log-macros-for-defining-categories-at-block-scope"> Macros for Defining Categories at Block Scope </a>
31/// * <a href="#ball_log-macro-for-defining-categories-at-class-scope"> Macro for Defining Categories at Class Scope </a>
32/// * <a href="#ball_log-macro-for-defining-categories-at-namespace-or-global-scope"> Macro for Defining Categories at Namespace or Global Scope </a>
33/// * <a href="#ball_log-macros-for-defining-hierarchical-categories"> Macros for Defining Hierarchical Categories </a>
34/// * <a href="#ball_log-macros-for-logging-records"> Macros for Logging Records </a>
35/// * <a href="#ball_log-macros-for-logging-code-blocks"> Macros for Logging Code Blocks </a>
36/// * <a href="#ball_log-utility-macros"> Utility Macros </a>
37/// * <a href="#ball_log-usage"> Usage </a>
38/// * <a href="#ball_log-example-1-a-basic-logging-example"> Example 1: A Basic Logging Example </a>
39/// * <a href="#ball_log-example-2-setting-the-current-log-category"> Example 2: Setting the Current Log Category </a>
40/// * <a href="#ball_log-example-3-c-io-streams-style-logging-macros"> Example 3: C++ IO Streams-Style Logging Macros </a>
41/// * <a href="#ball_log-example-4-printf-style-output"> Example 4: printf-Style Output </a>
42/// * <a href="#ball_log-example-5-dynamic-categories"> Example 5: Dynamic Categories </a>
43/// * <a href="#ball_log-example-6-rule-based-logging"> Example 6: Rule-Based Logging </a>
44/// * <a href="#ball_log-example-7-logging-using-a-callback"> Example 7: Logging Using a Callback </a>
45/// * <a href="#ball_log-example-8-class-scope-logging"> Example 8: Class-Scope Logging </a>
46///
47/// # Purpose {#ball_log-purpose}
48/// Provide macros and utility functions to facilitate logging.
49///
50/// # Classes {#ball_log-classes}
51///
52/// - ball::Log: namespace for logging utilities (for *internal* use only)
53///
54/// # Macros {#ball_log-macros}
55///
56/// - BALL_LOG_SET_CATEGORY(C): set a category for logging to the specified `C`
57/// - BALL_LOG_SET_DYNAMIC_CATEGORY(C): set a run-time-dependent category
58/// - BALL_LOG_SET_CLASS_CATEGORY(C): set a category in the scope of a class
59/// - BALL_LOG_SET_NAMESPACE_CATEGORY(C): set a category in a namespace
60/// - BALL_LOG_SET_CATEGORY_HIERARCHICALLY(C): set a category hierarchically
61/// - BALL_LOG_SET_DYNAMIC_CATEGORY_HIERARCHICALLY(C): set a run-time category
62/// - BALL_LOG_SET_CLASS_CATEGORY_HIERARCHICALLY(C): set a class category
63/// - BALL_LOG_SET_NAMESPACE_CATEGORY_HIERARCHICALLY(C): set a namespace category
64/// - BALL_LOG_TRACE: produce a log record with the `e_TRACE` severity level
65/// - BALL_LOG_DEBUG: produce a log record with the `e_DEBUG` severity level
66/// - BALL_LOG_INFO: produce a log record with the `e_INFO` severity level
67/// - BALL_LOG_WARN: produce a log record with the `e_WARN` severity level
68/// - BALL_LOG_ERROR: produce a log record with the `e_ERROR` severity level
69/// - BALL_LOG_FATAL: produce a log record with the `e_FATAL` severity level
70/// - BALL_LOG_STREAM(SEV): produce a log record with the specified `SEV` level
71/// - BALL_LOGCB_TRACE(CB): produce a `e_TRACE` log record using callback `CB`
72/// - BALL_LOGCB_DEBUG(CB): produce a `e_DEBUG` log record using callback `CB`
73/// - BALL_LOGCB_INFO(CB): produce an `e_INFO` log record using callback `CB`
74/// - BALL_LOGCB_WARN(CB): produce a `e_WARN` log record using callback `CB`
75/// - BALL_LOGCB_ERROR(CB): produce an `e_ERROR` log record using callback `CB`
76/// - BALL_LOGCB_FATAL(CB): produce a `e_FATAL` log record using callback `CB`
77/// - BALL_LOGCB_STREAM(SEV, CB): produce a `SEV` log record using callback
78/// - BALL_LOGVA_TRACE(MSG, ...): produce `e_TRACE` record using `printf` format
79/// - BALL_LOGVA_DEBUG(MSG, ...): produce `e_DEBUG` record using `printf` format
80/// - BALL_LOGVA_INFO( MSG, ...): produce `e_INFO` record using `printf` format
81/// - BALL_LOGVA_WARN( MSG, ...): produce `e_WARN` record using `printf` format
82/// - BALL_LOGVA_ERROR(MSG, ...): produce `e_ERROR` record using `printf` format
83/// - BALL_LOGVA_FATAL(MSG, ...): produce `e_FATAL` record using `printf` format
84/// - BALL_LOGVA(SEV, MSG, ...): produce a `SEV` log record using `printf` format
85/// - BALL_LOG_TRACE_BLOCK: set code block with `e_TRACE` condition of execution
86/// - BALL_LOG_DEBUG_BLOCK: set code block with `e_DEBUG` condition of execution
87/// - BALL_LOG_INFO_BLOCK: set a code block with `e_INFO` condition of execution
88/// - BALL_LOG_WARN_BLOCK: set a code block with `e_WARN` condition of execution
89/// - BALL_LOG_ERROR_BLOCK: set code block with `e_ERROR` condition of execution
90/// - BALL_LOG_FATAL_BLOCK: set code block with `e_FATAL` condition of execution
91/// - BALL_LOG_STREAM_BLOCK(SEV): set a code block with `SEV` condition
92/// - BALL_LOGCB_TRACE_BLOCK(CB): set `e_TRACE` block with the specified callback
93/// - BALL_LOGCB_DEBUG_BLOCK(CB): set `e_DEBUG` block with the specified callback
94/// - BALL_LOGCB_INFO_BLOCK(CB): set `e_INFO` block with the specified callback
95/// - BALL_LOGCB_WARN_BLOCK(CB): set `e_WARN` block with the specified callback
96/// - BALL_LOGCB_ERROR_BLOCK(CB): set an `e_ERROR` block with the specified `CB`
97/// - BALL_LOGCB_FATAL_BLOCK(CB): set `e_FATAL` block with the specified callback
98/// - BALL_LOGCB_STREAM_BLOCK(SEV, CB): set a `SEV` block with the specified `CB`
99/// - BALL_LOG_IS_ENABLED(SEV): indicate if `SEV` is severe enough for logging
100///
101/// @see ball_loggermanager, ball_category, ball_severity, ball_record
102///
103/// # Description {#ball_log-description}
104/// This component provides preprocessor macros and utility
105/// functions to facilitate use of the @ref ball_loggermanager component. In
106/// particular, the macros defined herein greatly simplify the mechanics of
107/// generating log records. The utility functions provided in `ball::Log` are
108/// intended only for use by the macros and should *not* be called directly.
109///
110/// The macros defined herein pertain to the logger manager singleton only, and
111/// not to any non-singleton instances of `ball::LoggerManager`. In particular,
112/// the macros do not have any effect unless the logger manager singleton is
113/// initialized. Note that the flow of control may pass through a use of any of
114/// the macros *before* the logger manager singleton has been initialized or
115/// *after* it has been destroyed; however, control should not pass through any
116/// macro use *during* logger manager singleton initialization or destruction.
117/// See {@ref ball_loggermanager |Logger Manager Singleton Initialization} for
118/// details on the recommended procedure for initializing the singleton.
119///
120/// ## Thread Safety {#ball_log-thread-safety}
121///
122///
123/// All macros defined in this component are thread-safe, and can be invoked
124/// concurrently by multiple threads.
125///
126/// Additionally, each use of a logging macro will create a distinct log record,
127/// and `ball::Observer` implementations (like those in `ball`) generally
128/// guarantee that output for different log records are not interleaved.
129///
130/// ## Macro Reference {#ball_log-macro-reference}
131///
132///
133/// This section documents the preprocessor macros defined in this component.
134///
135/// The first three macros described below are used to define categories, at
136/// either block scope or class scope, to which records are logged by the C++
137/// stream-based and `printf`-style logging macros (described further below).
138///
139/// ### Macros for Defining Categories at Block Scope {#ball_log-macros-for-defining-categories-at-block-scope}
140///
141///
142/// The following two macros are used to establish logging categories that have
143/// block scope:
144///
145/// `BALL_LOG_SET_CATEGORY(CATEGORY)`:
146/// Set a category for logging to the specified `CATEGORY` (assumed to be
147/// of type convertible to `const char *`). On the *first* invocation of
148/// this macro in a code block, the `ball::Log::setCategory` method is
149/// invoked to retrieve the address of an appropriate category structure
150/// for its scope; subsequent invocations will use a cached address of the
151/// category. (See the function-level documentation of
152/// `ball::Log::setCategory` for more information.) This macro must be
153/// used at block scope, and can be used at most once in any given block
154/// (or else a compiler diagnostic will result).
155///
156/// `BALL_LOG_SET_DYNAMIC_CATEGORY(CATEGORY)`:
157/// Set, *on* *EACH* *invocation*, a category for logging to the specified
158/// `CATEGORY` (assumed to be of type convertible to `const char *`). On
159/// *EVERY* invocation of this macro in a code block, the
160/// `ball::Log::setCategory` method is invoked to retrieve the address of
161/// an appropriate category structure for its scope; the address returned
162/// from `ball::Log::setCategory` is *NOT* cached for subsequent calls.
163/// (See the function-level documentation of `ball::Log::setCategory` for
164/// more information.) This macro must be used at block scope and can be
165/// used at most once in any given block (or else a compiler diagnostic
166/// will result). Note that this macro should be used to create categories
167/// that depend on *RUN-TIME* values only (e.g., LUW or UUID).
168///
169/// There can be at most one use of either `BALL_LOG_SET_CATEGORY` or
170/// `BALL_LOG_SET_DYNAMIC_CATEGORY` in any given block (or else a compiler
171/// diagnostic will result). Note that categories that are set using these
172/// macros, including dynamic categories, are not destroyed until the logger
173/// manager singleton is destroyed.
174///
175/// ### Macro for Defining Categories at Class Scope {#ball_log-macro-for-defining-categories-at-class-scope}
176///
177///
178/// The following macro is used to establish logging categories that have class
179/// scope:
180///
181/// `BALL_LOG_SET_CLASS_CATEGORY(CATEGORY)`:
182/// Set a category for logging to the specified `CATEGORY` (assumed to be
183/// of type convertible to `const char *`) in the scope of the class within
184/// which this macro is used. Similar to `BALL_LOG_SET_CATEGORY`, the
185/// category is set *once* only, the first time that it is accessed (i.e.,
186/// it is not a dynamic category). This macro must be used, at most once,
187/// within the definition of a class or class template (or else a compiler
188/// diagnostic will result). Note that use of this macro may occur in
189/// either a `public`, `private`, or `protected` section of a class's
190/// interface, although `private` should be preferred.
191///
192/// Note that similar to block-scope categories (see `BALL_LOG_SET_CATEGORY` and
193/// `BALL_LOG_SET_DYNAMIC_CATEGORY`), class-scope categories are not destroyed
194/// until the logger manager singleton is destroyed.
195///
196/// ### Macro for Defining Categories at Namespace or Global Scope {#ball_log-macro-for-defining-categories-at-namespace-or-global-scope}
197///
198///
199/// The following macro is used to establish logging categories that have
200/// namespace or global scope:
201///
202/// `BALL_LOG_SET_NAMESPACE_CATEGORY(CATEGORY)`:
203/// Set a category for logging to the specified `CATEGORY` (assumed to be
204/// of type convertible to `const char *`) in the namespace (or global)
205/// scope within which this macro is used. Similar to
206/// `BALL_LOG_SET_CATEGORY`, the category is set *once* only, the first
207/// time that it is accessed (i.e., it is not a dynamic category). This
208/// macro may be used, in `.cpp` files *only*, at most once in any given
209/// namespace and at most once at global scope (or else a compiler
210/// diagnostic will result). Do *NOT* use this macro in `.h` files.
211///
212/// Note that similar to block-scope categories (see `BALL_LOG_SET_CATEGORY` and
213/// `BALL_LOG_SET_DYNAMIC_CATEGORY`), namespace-scope categories are not
214/// destroyed until the logger manager singleton is destroyed.
215///
216/// ### Macros for Defining Hierarchical Categories {#ball_log-macros-for-defining-hierarchical-categories}
217///
218///
219/// The following macros are used to establish logging categories having
220/// thresholds that are given by the existing non-default category whose name
221/// matches the longest prefix of the new category's name (i.e., the threshold
222/// levels of new categories are determined "hierarchically" from existing
223/// categories rather than from the default threshold levels of the logger
224/// manager singleton).
225///
226/// `BALL_LOG_SET_CATEGORY_HIERARCHICALLY(CATEGORY)`
227/// Set a category for logging to the specified `CATEGORY` (assumed to be
228/// of type convertible to `const char *`). On the *first* invocation of
229/// this macro in a code block, the `ball::Log::setCategoryHierarchically`
230/// method is invoked to retrieve the address of an appropriate category
231/// structure for its scope; subsequent invocations will use a cached
232/// address of the category. (See the function-level documentation of
233/// `ball::Log::setCategoryHierarchically` for more information.) This
234/// macro must be used at block scope, and can be used at most once in any
235/// given block (or else a compiler diagnostic will result).
236///
237/// `BALL_LOG_SET_DYNAMIC_CATEGORY_HIERARCHICALLY(CATEGORY)`:
238/// Set, *on* *EACH* *invocation*, a category for logging to the specified
239/// `CATEGORY` (assumed to be of type convertible to `const char *`). On
240/// *EVERY* invocation of this macro in a code block, the
241/// `ball::Log::setCategoryHierarchically` method is invoked to retrieve
242/// the address of an appropriate category structure for its scope; the
243/// address returned from `ball::Log::setCategoryHierarchically` is *NOT*
244/// cached for subsequent calls. (See the function-level documentation of
245/// `ball::Log::setCategoryHierarchically` for more information.) This
246/// macro must be used at block scope and can be used at most once in any
247/// given block (or else a compiler diagnostic will result). Note that
248/// this macro should be used to create categories that depend on
249/// *RUN-TIME* values only (e.g., LUW or UUID).
250///
251/// `BALL_LOG_SET_CLASS_CATEGORY_HIERARCHICALLY(CATEGORY)`
252/// Set a category for logging to the specified `CATEGORY` (assumed to be
253/// of type convertible to `const char *`) in the scope of the class within
254/// which this macro is used. Similar to
255/// `BALL_LOG_SET_CATEGORY_HIERARCHICALLY`, the category is set *once*
256/// only, using the `ball::Log::setCategoryHierarchically` function, the
257/// first time that it is accessed (i.e., it is not a dynamic category).
258/// (See the function-level documentation for
259/// `ball::Log::setCategoryHierarchically` for more information.) This
260/// macro must be used, at most once, within the definition of a class or
261/// class template (or else a compiler diagnostic will result). Note that
262/// use of this macro may occur in either a `public`, `private`, or
263/// `protected` section of a class's interface, although `private` should
264/// be preferred.
265///
266/// `BALL_LOG_SET_NAMESPACE_CATEGORY_HIERARCHICALLY(CATEGORY)`
267/// Set a category for logging to the specified `CATEGORY` (assumed to be
268/// of type convertible to `const char *`) in the namespace (or global)
269/// scope within which this macro is used. Similar to
270/// `BALL_LOG_SET_CATEGORY_HIERARCHICALLY`, the category is set *once*
271/// only, using the `ball::Log::setCategoryHierarchically` function, the
272/// first time that it is accessed (i.e., it is not a dynamic category).
273/// (See the function-level documentation for
274/// `ball::Log::setCategoryHierarchically` for more information.) This
275/// macro may be used, in `.cpp` files *only*, at most once in any given
276/// namespace and at most once at global scope (or else a compiler
277/// diagnostic will result). Do *NOT* use this macro in `.h` files.
278///
279/// ### Macros for Logging Records {#ball_log-macros-for-logging-records}
280///
281///
282/// The macros defined in this subsection are the ones that are actually used to
283/// produce log records. A use of any one of the logging macros requires that a
284/// logging category (as established by the macros defined above) be in scope at
285/// the point where the macro is used. Note that the formatted string that is
286/// generated for the message attribute of each log record includes the category
287/// that is in scope and the filename as established by the standard `__FILE__`
288/// macro.
289///
290/// The code within any logging statement/code block must not produce any side
291/// effects because it may or may not be executed based on run-time
292/// configuration of the `ball` logging subsystem:
293/// @code
294/// BALL_LOG_INFO << ++i; // (!) May or may not be incremented
295///
296/// BALL_LOG_TRACE_BLOCK {
297/// processRequest(...); // (!) May or may not be called
298/// }
299/// @endcode
300///
301/// A set of macros based on C++ streams, `BALL_LOG_TRACE`, `BALL_LOG_DEBUG`,
302/// `BALL_LOG_INFO`, `BALL_LOG_WARN`, `BALL_LOG_ERROR`, and `BALL_LOG_FATAL`,
303/// are the ones most commonly used for logging. They have the following usage
304/// pattern:
305/// @code
306/// BALL_LOG_TRACE << X << Y ... ;
307/// BALL_LOG_DEBUG << X << Y ... ;
308/// BALL_LOG_INFO << X << Y ... ;
309/// BALL_LOG_WARN << X << Y ... ;
310/// BALL_LOG_ERROR << X << Y ... ;
311/// BALL_LOG_FATAL << X << Y ... ;
312/// where X, Y, ... represents any sequence of values for which
313/// `operator<<` is defined. The resulting formatted message string is
314/// logged with the severity indicated by the name of the macro
315/// (e.g., `BALL_LOG_TRACE` logs with severity `ball::Severity::e_TRACE`).
316/// @endcode
317/// A closely-related macro also based on C++ streams, `BALL_LOG_STREAM`,
318/// requires that the severity be explicitly supplied as an argument:
319/// @code
320/// BALL_LOG_STREAM(SEVERITY) << X << Y ... ;
321/// where X, Y, ... represents any sequence of values for which
322/// `operator<<` is defined. The resulting formatted message string is
323/// logged with the specified `SEVERITY`.
324/// @endcode
325/// Another set of macros based on C++ streams, similar to `BALL_LOG_TRACE`,
326/// etc., allow the caller to specify a "callback" function that is passed the
327/// `ball::UserFields *` used to represent the user fields of a log record.
328/// `BALL_LOGCB_TRACE`, `BALL_LOGCB_DEBUG`, `BALL_LOGCB_INFO`,
329/// `BALL_LOGCB_WARN`, `BALL_LOGCB_ERROR`, and `BALL_LOGCB_FATAL` have the
330/// following usage pattern:
331/// @code
332/// BALL_LOGCB_TRACE(CALLBACK) << X << Y ... ;
333/// BALL_LOGCB_DEBUG(CALLBACK) << X << Y ... ;
334/// BALL_LOGCB_INFO(CALLBACK) << X << Y ... ;
335/// BALL_LOGCB_WARN(CALLBACK) << X << Y ... ;
336/// BALL_LOGCB_ERROR(CALLBACK) << X << Y ... ;
337/// BALL_LOGCB_FATAL(CALLBACK) << X << Y ... ;
338/// where X, Y, ... represents any sequence of values for which
339/// `operator<<` is defined and `CALLBACK` is a callback taking a
340/// `ball::UserFields *` as an argument. The resulting formatted message
341/// string is logged with the severity indicated by the name of the macro
342/// (e.g., `BALL_LOGCB_ERROR` logs with severity
343/// `ball::Severity::e_ERROR`). The generated log record will contain the
344/// `ball::UserFields` representing user fields as populated by `CALLBACK`.
345/// Note that the callback supplied to the logging macro must match the
346/// prototype `void (*)(ball::UserFields *)`.
347/// @endcode
348/// A closely-related macro also based on C++ streams, `BALL_LOGCB_STREAM`,
349/// requires that the severity be explicitly supplied as an argument:
350/// @code
351/// BALL_LOGCB_STREAM(SEVERITY, CALLBACK) << X << Y ... ;
352/// where X, Y, ... represents any sequence of values for which
353/// `operator<<` is defined. The resulting formatted message string is
354/// logged with the specified `SEVERITY`. The generated log record will
355/// contain the `ball::UserFields` representing user fields as populated by
356/// `CALLBACK`. Note that the callback supplied to the logging macro must
357/// match the prototype `void (*)(ball::UserFields *)`.
358/// @endcode
359/// The remaining macros are based on `printf`-style format specifications:
360/// @code
361/// BALL_LOGVA_TRACE(MSG, ...);
362/// BALL_LOGVA_DEBUG(MSG, ...);
363/// BALL_LOGVA_INFO( MSG, ...);
364/// BALL_LOGVA_WARN( MSG, ...);
365/// BALL_LOGVA_ERROR(MSG, ...);
366/// BALL_LOGVA_FATAL(MSG, ...);
367/// Format the specified `...` optional arguments, if any, according to the
368/// `printf`-style format specification in the specified `MSG` (assumed to
369/// be of type convertible to `const char *`) and log the resulting
370/// formatted message string with the severity indicated by the name of the
371/// macro (e.g., `BALL_LOGVA_INFO` logs with severity
372/// `ball::Severity::e_INFO`). The behavior is undefined unless the number
373/// and types of optional arguments are compatible with the format
374/// specification in `MSG`. Note that each use of these macros must be
375/// terminated by a `;`.
376/// @endcode
377/// A closely-related `printf`-style macro, `BALL_LOGVA`, requires that the
378/// severity be explicitly supplied as an argument:
379/// @code
380/// BALL_LOGVA(SEVERITY, MSG, ...);
381/// Format the specified `...` optional arguments, if any, according to the
382/// `printf`-style format specification in the specified `MSG` (assumed to
383/// be of type convertible to `const char *`) and log the resulting
384/// formatted message string with the specified `SEVERITY`. The behavior
385/// is undefined unless the number and types of optional arguments are
386/// compatible with the format specification in `MSG`. Note that each use
387/// of this macro must be terminated by a `;`.
388/// @endcode
389///
390/// ### Macros for Logging Code Blocks {#ball_log-macros-for-logging-code-blocks}
391///
392///
393/// The following macros allow the caller to start a code block that will be
394/// conditionally executed depending on the current logging threshold of the
395/// category that is in scope of those macros:
396/// @code
397/// BALL_LOG_TRACE_BLOCK { ... }
398/// BALL_LOG_DEBUG_BLOCK { ... }
399/// BALL_LOG_INFO_BLOCK { ... }
400/// BALL_LOG_WARN_BLOCK { ... }
401/// BALL_LOG_ERROR_BLOCK { ... }
402/// BALL_LOG_FATAL_BLOCK { ... }
403/// @endcode
404/// A closely-related macro, `BALL_LOG_STREAM_BLOCK`, requires that the severity
405/// be explicitly supplied as an argument:
406/// @code
407/// BALL_LOG_STREAM_BLOCK(SEVERITY) { ... }
408/// @endcode
409/// Another set of macros, similar to `BALL_LOG_*_BLOCK`, allow the caller to
410/// specify a "callback" function that is passed the `ball::UserFields *` used
411/// to represent the user fields of a log record:
412/// @code
413/// BALL_LOGCB_TRACE_BLOCK(CALLBACK) { ... }
414/// BALL_LOGCB_DEBUG_BLOCK(CALLBACK) { ... }
415/// BALL_LOGCB_INFO_BLOCK(CALLBACK) { ... }
416/// BALL_LOGCB_WARN_BLOCK(CALLBACK) { ... }
417/// BALL_LOGCB_ERROR_BLOCK(CALLBACK) { ... }
418/// BALL_LOGCB_FATAL_BLOCK(CALLBACK) { ... }
419/// @endcode
420/// A closely-related macro, `BALL_LOGCB_STREAM_BLOCK`, requires that the
421/// severity be explicitly supplied as an argument:
422/// @code
423/// BALL_LOGCB_STREAM_BLOCK(SEVERITY, CALLBACK) { ... }
424/// @endcode
425/// Within the logging code block a special macro, `BALL_LOG_OUTPUT_STREAM`,
426/// provides access to the log stream.
427///
428/// ### Utility Macros {#ball_log-utility-macros}
429///
430///
431/// The following utility macro is intended for special-purpose use for
432/// fine-tuning logging behavior. A use of this macro requires that a logging
433/// category (as established by the macros defined above) be in scope at the
434/// point where the macro is used.
435/// @code
436/// BALL_LOG_IS_ENABLED(SEVERITY)
437/// Return `true` if the specified `SEVERITY` is at least as severe as any
438/// of the threshold levels of the logging category that is in scope, and
439/// `false` otherwise.
440/// @endcode
441///
442/// ## Usage {#ball_log-usage}
443///
444///
445/// The following code fragments illustrate the standard pattern of macro usage.
446///
447/// ### Example 1: A Basic Logging Example {#ball_log-example-1-a-basic-logging-example}
448///
449///
450/// The following trivial example shows how to use the logging macros to log
451/// messages at various levels of severity.
452///
453/// First, we initialize the log category within the context of this function.
454/// The logging macros such as `BALL_LOG_ERROR` will not compile unless a
455/// category has been specified in the current lexical scope:
456/// @code
457/// BALL_LOG_SET_CATEGORY("EXAMPLE.CATEGORY");
458/// @endcode
459/// Then, we record messages at various levels of severity. These messages will
460/// be conditionally written to the log depending on the current logging
461/// threshold of the category (configured using the `ball::LoggerManager`
462/// singleton):
463/// @code
464/// BALL_LOG_FATAL << "Write this message to the log if the log threshold "
465/// << "is above 'ball::Severity::e_FATAL' (i.e., 32).";
466///
467/// BALL_LOG_TRACE << "Write this message to the log if the log threshold "
468/// << "is above 'ball::Severity::e_TRACE' (i.e., 192).";
469/// @endcode
470/// Next, we demonstrate how to use proprietary code within logging macros.
471/// Suppose you want to add the content of a vector to the log trace:
472/// @code
473/// bsl::vector<int> myVector(4, 328);
474/// BALL_LOG_TRACE_BLOCK {
475/// BALL_LOG_OUTPUT_STREAM << "myVector = [ ";
476/// unsigned int position = 0;
477/// for (bsl::vector<int>::const_iterator it = myVector.begin(),
478/// end = myVector.end();
479/// it != end;
480/// ++it, ++position) {
481/// BALL_LOG_OUTPUT_STREAM << position << ':' << *it << ' ';
482/// }
483/// BALL_LOG_OUTPUT_STREAM << ']';
484/// }
485/// @endcode
486/// Note that the code block will be conditionally executed depending on the
487/// current logging threshold of the category. The code within the block must
488/// not produce any side effects, because its execution depends on the current
489/// logging configuration. The special macro `BALL_LOG_OUTPUT_STREAM` provides
490/// access to the log stream within the block.
491///
492/// ### Example 2: Setting the Current Log Category {#ball_log-example-2-setting-the-current-log-category}
493///
494///
495/// This example provides more detail on setting the log category in the
496/// current lexical scope. The following macro instantiation sets the category
497/// for logging to be "EQUITY.NASD" in the enclosing lexical scope:
498/// @code
499/// BALL_LOG_SET_CATEGORY("EQUITY.NASD")
500/// @endcode
501/// Note that this macro must not be used at file scope and it can be used at
502/// most once in any given block (or else a compiler diagnostic will result). A
503/// different category may be established to override one that is in effect, but
504/// it must occur in a nested scope. In any case, a use of this macro (or of
505/// `BALL_LOG_SET_DYNAMIC_CATEGORY`) must be visible from within the lexical
506/// scope of every use of the log-generating macros. The following fragment of
507/// code shows how to set a different category in a nested inner block that
508/// hides a category set in an enclosing block:
509/// @code
510/// void logIt()
511/// {
512/// BALL_LOG_SET_CATEGORY("EQUITY.NASD")
513///
514/// // Logging to category "EQUITY.NASD" unless overridden in a nested
515/// // block.
516/// // [*] ...
517///
518/// {
519/// // [*] ...
520/// // Still logging to category "EQUITY.NASD".
521///
522/// BALL_LOG_SET_CATEGORY("EQUITY.NASD.SUNW")
523///
524/// // Now logging to category "EQUITY.NASD.SUNW".
525/// // [*] ...
526/// }
527/// // Again logging to category "EQUITY.NASD".
528/// // [*] ...
529/// }
530/// @endcode
531/// Within `logIt`, a requisite logging category is visible at each of the
532/// locations marked by `[*]`.
533///
534/// ### Example 3: C++ IO Streams-Style Logging Macros {#ball_log-example-3-c-io-streams-style-logging-macros}
535///
536///
537/// The preferred logging method we use, the `iostream`-style macros such as
538/// `BALL_LOG_INFO`, allow streaming via the `bsl::ostream` `class` and the C++
539/// stream operator `<<`. An advantage the C++ streaming style has over the
540/// `printf` style output (shown below in example 4) is that complex types often
541/// have the `operator<<(ostream&, const TYPE&)` function overloaded so that
542/// they are able to be easily streamed to output. We demonstrate this here
543/// using C++ streaming to stream a `bdlt::Date` to output:
544/// @code
545/// int lotSize = 400;
546/// const char *ticker = "SUNW";
547/// double price = 5.65;
548///
549/// // Trading on a market that settles 3 days in the future.
550///
551/// bdlt::Date settle = bdlt::CurrentTime::local().date() + 3;
552///
553/// BALL_LOG_SET_CATEGORY("EQUITY.NASD")
554/// @endcode
555/// We are logging with category "EQUITY.NASD", which is configured for a
556/// pass-through level of `e_INFO`, from here on. We output a line using the
557/// `BALL_LOG_INFO` macro:
558/// @code
559/// BALL_LOG_INFO << "[1] " << lotSize
560/// << " shares of " << ticker
561/// << " sold at " << price
562/// << " settlement date " << settle;
563/// @endcode
564/// The above results in the following single-line message being output:
565/// @code
566/// <ts> <pid> <tid> INFO x.cpp 1161 EQUITY.NASD [1] 400 shares of SUNW sold
567/// at 5.65 settlement date 17FEB2017
568/// @endcode
569/// `<ts>` is the timestamp, `<pid>` is the process id, `<tid>` is the thread
570/// id, `x.cpp` is the expansion of the `__FILE__` macro that is the name of the
571/// source file containing the call, 1161 is the line number of the call, and
572/// the trailing date following "settlement date" is the value of `settle`.
573///
574/// Next, we set the category to "EQUITY.NASD.SUNW", which has been defined with
575/// `ball::Administration::addCategory` with its pass-through level set to
576/// `e_INFO` and the trigger levels set at or above `e_ERROR`, so a level of
577/// `e_WARN` also passes through:
578/// @code
579/// {
580/// BALL_LOG_SET_CATEGORY("EQUITY.NASD.SUNW")
581///
582/// // Now logging with category "EQUITY.NASD.SUNW".
583///
584/// BALL_LOG_WARN << "[2] " << lotSize
585/// << " shares of " << ticker
586/// << " sold at " << price
587/// << " settlement date " << settle;
588/// }
589/// @endcode
590/// The above results in the following message to category "EQUITY.NASD.SUNW":
591/// @code
592/// <ts> <pid> <tid> WARN x.cpp 1185 EQUITY.NASD.SUNW [2] 400 shares of SUNW
593/// sold at 5.65 settlement date 17FEB2017
594/// @endcode
595/// Now, the category "EQUITY.NASD.SUNW" just went out of scope and category
596/// "EQUITY.NASD" is visible again, so it applies to the following:
597/// @code
598/// BALL_LOG_INFO << "[3] " << lotSize
599/// << " shares of " << ticker
600/// << " sold at " << price
601/// << " settlement date " << settle;
602/// @endcode
603/// Finally, the above results in the following single-line message being
604/// output:
605/// @code
606/// <ts> <pid> <tid> INFO x.cpp 1198 EQUITY.NASD [3] 400 shares of SUNW sold
607/// at 5.65 settlement date 17FEB2017
608/// @endcode
609/// The settlement date was appended to the message as a simple illustration of
610/// the added flexibility provided by the C++ stream-based macros. This last
611/// message was logged to category "EQUITY.NASD" at severity level
612/// `ball::Severity::e_INFO`.
613///
614/// The C++ stream-based macros, as opposed to the `printf`-style macros, ensure
615/// at compile-time that no run-time format mismatches will occur. Use of the
616/// stream-based logging style exclusively will likely lead to clearer, more
617/// maintainable code with fewer initial defects.
618///
619/// Note that all uses of the log-generating macros, both `printf`-style and C++
620/// stream-based, *must* occur within function scope (i.e., not at file scope).
621///
622/// ### Example 4: printf-Style Output {#ball_log-example-4-printf-style-output}
623///
624///
625/// In the following example, we expand the `logIt` function (defined above) to
626/// log two messages using the `BALL_LOGVA_INFO` logging macro provided by this
627/// component. This variadic macro takes a format string and a variable-length
628/// series of arguments, similar to `printf`.
629/// @code
630/// int lotSize = 400;
631/// const char *ticker = "SUNW";
632/// double price = 5.65;
633///
634/// // Trading on a market that settles 3 days in the future.
635///
636/// bdlt::Date settleDate = bdlt::CurrentTime::local().date() + 3;
637/// @endcode
638/// Because we can't easily `printf` complex types like `bdlt::Date` or
639/// `bsl::string`, we have to convert `settleDate` to a `const char *`
640/// ourselves. Note that all this additional work was unnecessary in Example 3
641/// when we used the C++ `iostream`-style, rather than the `printf`-style,
642/// macros.
643/// @code
644/// bsl::ostringstream settleOss;
645/// settleOss << settleDate;
646/// const bsl::string& settleStr = settleOss.str();
647/// const char *settle = settleStr.c_str();
648/// @endcode
649/// We set logging with category "EQUITY.NASD", which was configured for a
650/// pass-through severity level of `e_INFO`, and call `BALL_LOGVA_INFO` to print
651/// our trade:
652/// @code
653/// BALL_LOG_SET_CATEGORY("EQUITY.NASD")
654///
655/// BALL_LOGVA_INFO("[4] %d shares of %s sold at %f settlement date %s\n",
656/// lotSize, ticker, price, settle);
657/// @endcode
658/// The above results in the following single-line message being output to
659/// category "EQUITY.NASD.SUNW" at severity level `ball::Severity::e_INFO`:
660/// @code
661/// <ts> <pid> <tid> INFO x.cpp 1256 EQUITY.NASD [4] 400 shares of SUNW sold
662/// at 5.650000 settlement date 17FEB2017
663/// @endcode
664/// In the above, `<ts>` is the timestamp, `<pid>` is the process id, `<tid>` is
665/// the thread id, `x.cpp` is the expansion of the `__FILE__` macro that is the
666/// name of the source file containing the call, and 1256 is the line number of
667/// the call.
668///
669/// Note that the first argument supplied to the `BALL_LOGVA_INFO` macro is a
670/// `printf`-style format specification.
671///
672/// Next, we set the category to "EQUITY.NASD.SUNW", which is configured for a
673/// pass-through severity level of `e_INFO`:
674/// @code
675/// {
676/// BALL_LOG_SET_CATEGORY("EQUITY.NASD.SUNW")
677///
678/// // Now logging with category "EQUITY.NASD.SUNW".
679///
680/// BALL_LOGVA_WARN("[5] %d shares of %s sold at %f settlement date %s\n",
681/// lotSize, ticker, price, settle);
682/// }
683/// @endcode
684/// The above results in the following single-line message to category
685/// "EQUITY.NASD.SUNW":
686/// @code
687/// <ts> <pid> <tid> WARN x.cpp 1281 EQUITY.NASD.SUNW [5] 400 shares of SUNW
688/// sold at 5.650000 settlement date 17FEB2017
689/// @endcode
690/// Now, the category "EQUITY.NASD.SUNW" just went out of scope and category
691/// "EQUITY.NASD" is visible again, so it applies to the following:
692/// @code
693/// BALL_LOGVA_INFO("[6] %d shares of %s sold at %f settlement date %s\n",
694/// lotSize, ticker, price, settle);
695/// @endcode
696/// Finally, the above results in the following single-line message being
697/// output:
698/// @code
699/// <ts> <pid> <tid> INFO x.cpp 1294 EQUITY.NASD [6] 400 shares of SUNW sold
700/// at 5.650000 settlement date 17FEB2017
701/// @endcode
702///
703/// ### Example 5: Dynamic Categories {#ball_log-example-5-dynamic-categories}
704///
705///
706/// Logging must sometimes be controlled by parameters that are not available
707/// until run-time. The `BALL_LOG_SET_DYNAMIC_CATEGORY` macro sets a category
708/// each time it is invoked (unlike `BALL_LOG_SET_CATEGORY`, which sets a
709/// category only on the first invocation and uses the cached address of the
710/// category on subsequent invocations). The category name in the following
711/// `processSecurity` function is a combination of a static prefix and the
712/// (dynamic) `exchange` argument:
713/// @code
714/// void processSecurity(const char *security, const char *exchange)
715/// {
716/// bsl::string categoryName("EXCHANGE:");
717/// categoryName.append(exchange);
718///
719/// BALL_LOG_SET_DYNAMIC_CATEGORY(categoryName.c_str());
720///
721/// BALL_LOG_TRACE << "processing: " << security;
722///
723/// // ...
724/// }
725/// @endcode
726/// Now logging can be controlled independently for each `exchange`.
727///
728/// *WARNING*: Along with the added flexibility provided by dynamic categories
729/// comes the additional overhead of computing and setting a category on each
730/// invocation. Consequently, dynamic categories should be used *SPARINGLY* in
731/// most applications.
732///
733/// ### Example 6: Rule-Based Logging {#ball_log-example-6-rule-based-logging}
734///
735///
736/// The following example demonstrates the use of attributes and rules to
737/// conditionally enable logging.
738///
739/// We start by defining a function, `processData`, that is passed data in a
740/// `vector<char>` and information about the user who sent the data. This
741/// example function performs no actual processing, but does log a single
742/// message at the `ball::Severity::e_DEBUG` threshold level. The `processData`
743/// function also adds the user information passed to this function to the
744/// thread's attribute context. We will use these attributes later, to create a
745/// logging rule that enables verbose logging only for a particular user.
746/// @code
747/// /// Process the specified `data` associated with the specified Bloomberg
748/// /// `uuid`, `luw`, and `terminalNumber`.
749/// void processData(int uuid,
750/// int luw,
751/// int terminalNumber,
752/// const bsl::vector<char>& data)
753/// {
754/// (void)data; // suppress "unused" warning
755/// @endcode
756/// We add our attributes using `ball::ScopedAttribute`, which adds an attribute
757/// container with one attribute to a list of containers. This is easy and
758/// efficient if the number of attributes is small, but should not be used if
759/// there are a large number of attributes. If motivated, we could use
760/// `ball::DefaultAttributeContainer`, which provides an efficient container for
761/// a large number of attributes, or even create a more efficient attribute
762/// container implementation specifically for these three attributes (uuid, luw,
763/// and terminalNumber). See @ref ball_scopedattributes (plural) for an example
764/// of using a different attribute container, and @ref ball_attributecontainer
765/// for an example of creating a custom attribute container.
766/// @code
767/// // We use `ball::ScopedAttribute` here because the number of
768/// // attributes is relatively small.
769///
770/// ball::ScopedAttribute uuidAttribute("mylibrary.uuid", uuid);
771/// ball::ScopedAttribute luwAttribute("mylibrary.luw", luw);
772/// ball::ScopedAttribute termNumAttribute("mylibrary.terminalNumber",
773/// terminalNumber);
774/// @endcode
775/// In this simplified example we perform no actual processing, and simply log
776/// a message at the `ball::Severity::e_DEBUG` level.
777/// @code
778/// BALL_LOG_SET_CATEGORY("EXAMPLE.CATEGORY");
779///
780/// BALL_LOG_DEBUG << "An example message";
781/// @endcode
782/// Notice that if we were not using a "scoped" attribute container like that
783/// provided automatically by `ball::ScopedAttribute` (e.g., if we were using a
784/// local `ball::DefaultAttributeContainer` instead), then the container
785/// **must** be removed from the `ball::AttributeContext` before it is
786/// destroyed! See @ref ball_scopedattributes (plural) for an example.
787/// @code
788/// }
789/// @endcode
790/// Next we demonstrate how to create a logging rule that sets the pass-through
791/// logging threshold to `ball::Severity::e_TRACE` (i.e., enables verbose
792/// logging) for a particular user when calling the `processData` function
793/// defined above.
794///
795/// We start by creating the singleton logger manager that we configure with
796/// the stream observer and a default configuration. We then call the
797/// `processData` function: This first call to `processData` will not result in
798/// any logged messages because `processData` logs its message at the
799/// `ball::Severity::e_DEBUG` level, which is below the default configured
800/// logging threshold.
801/// @code
802/// ball::LoggerManagerConfiguration lmConfig;
803/// ball::LoggerManagerScopedGuard lmGuard(lmConfig);
804///
805/// bsl::shared_ptr<ball::StreamObserver> observer =
806/// bsl::make_shared<ball::StreamObserver>(&bsl::cout);
807///
808/// ball::LoggerManager::singleton().registerObserver(observer, "default");
809///
810/// BALL_LOG_SET_CATEGORY("EXAMPLE.CATEGORY");
811///
812/// bsl::vector<char> message;
813///
814/// BALL_LOG_ERROR << "Processing the first message.";
815/// processData(3938908, 2, 9001, message);
816/// @endcode
817/// Now we add a logging rule, setting the pass-through threshold to be
818/// `ball::Severity::e_TRACE` (i.e., enabling verbose logging) if the thread's
819/// context contains an attribute with name "mylibrary.uuid" with value 3938908.
820/// Note that we use the wild-card value `*` for the category so that the
821/// `ball::Rule` rule will apply to all categories.
822/// @code
823/// ball::Rule rule("*", 0, ball::Severity::e_TRACE, 0, 0);
824/// rule.addAttribute(ball::ManagedAttribute("mylibrary.uuid", 3938908));
825/// ball::LoggerManager::singleton().addRule(rule);
826///
827/// BALL_LOG_ERROR << "Processing the second message.";
828/// processData(3938908, 2, 9001, message);
829/// @endcode
830/// The final call to the `processData` function below, passes a `uuid` of
831/// 2171395 (not 3938908) so the logging rule we defined will *not* apply and no
832/// message will be logged.
833/// @code
834/// BALL_LOG_ERROR << "Processing the third message.";
835/// processData(2171395, 2, 9001, message);
836/// @endcode
837/// The resulting logged output for this example looks like the following:
838/// @code
839/// ERROR example.cpp:105 EXAMPLE.CATEGORY Processing the first message.
840/// ERROR example.cpp:117 EXAMPLE.CATEGORY Processing the second message.
841/// DEBUG example.cpp:35 EXAMPLE.CATEGORY An example message
842/// ERROR example.cpp:129 EXAMPLE.CATEGORY Processing the third message.
843/// @endcode
844///
845/// ### Example 7: Logging Using a Callback {#ball_log-example-7-logging-using-a-callback}
846///
847///
848/// The following example demonstrates how to register a logging callback. The
849/// C++ stream-based macros that take a callback are particularly useful to
850/// seamlessly populate the user fields of a record, thus simplifying the
851/// logging line.
852///
853/// We define a callback function `populateUsingPoint` that appends to the
854/// specified `fields` the attributes of the `point` to log:
855/// @code
856/// /// Append to the specified `list` the name, x value, and y value of
857/// /// the specified `point`.
858/// void populateUsingPoint(ball::UserFields *fields, const Point& point)
859/// {
860/// fields->appendString(point.name());
861/// fields->appendInt64(point.x());
862/// fields->appendInt64(point.y());
863/// }
864///
865/// int validatePoint(const Point& point)
866/// {
867/// BALL_LOG_SET_CATEGORY("EXAMPLE.CATEGORY");
868/// @endcode
869/// We now bind our callback function `populateUsingPoint` and the supplied
870/// `point` to a functor object we will pass to the logging callback. Note
871/// that the callback supplied to the logging macro must match the prototype
872/// `void (*)(ball::UserFields *)`.
873/// @code
874/// bsl::function <void(ball::UserFields *)> callback;
875/// callback = bdlf::BindUtil::bind(&populateUsingPoint,
876/// bdlf::PlaceHolders::_1,
877/// point);
878///
879/// int numErrors = 0;
880/// if (point.x() > 255) {
881/// BALL_LOGCB_ERROR(callback) << "X > 255";
882/// ++numErrors;
883/// }
884/// if (point.x() < -255) {
885/// BALL_LOGCB_ERROR(callback) << "X < -255";
886/// ++numErrors;
887/// }
888/// if (point.y() > 255) {
889/// BALL_LOGCB_ERROR(callback) << "Y > 255";
890/// ++numErrors;
891/// }
892/// if (point.y() < -255) {
893/// BALL_LOGCB_ERROR(callback) << "Y < -255";
894/// ++numErrors;
895/// }
896/// return numErrors;
897/// }
898/// @endcode
899///
900/// ### Example 8: Class-Scope Logging {#ball_log-example-8-class-scope-logging}
901///
902///
903/// The following example demonstrates how to define and use logging categories
904/// that have class scope.
905///
906/// First, we define a class, `Thing`, for which we want to do class-scope
907/// logging. The use of the `BALL_LOG_SET_CLASS_CATEGORY` macro generates the
908/// requisite declarations within the definition of the class. We have used the
909/// macro in a `private` section of the interface, which should be preferred,
910/// but `public` (or `protected`) is fine, too:
911/// @code
912/// // pckg_thing.h
913/// namespace pckg {
914///
915/// class Thing {
916/// // ...
917///
918/// private:
919/// BALL_LOG_SET_CLASS_CATEGORY("PCKG.THING");
920///
921/// public:
922/// // ...
923///
924/// // MANIPULATORS
925///
926/// /// Log to the class-scope category "PCKG.THING" if the specified
927/// /// `useClassCategory` flag is `true`, and to the block-scope
928/// /// category "X.Y.Z" otherwise.
929/// void outOfLineMethodThatLogs(bool useClassCategory);
930///
931/// // ...
932///
933/// // ACCESSORS
934///
935/// /// Log a record to the class-scope category "PCKG.THING".
936/// void inlineMethodThatLogs() const;
937/// };
938/// @endcode
939/// Next, we define the `inlineMethodThatLogs` method `inline` within the header
940/// file and log to the class-scope category using `BALL_LOG_TRACE`. Since
941/// there is no other category in scope, the record is necessarily logged to the
942/// "PCKG.THING" category that is within the scope of the `Thing` class:
943/// @code
944/// // ...
945///
946/// // ACCESSORS
947/// inline
948/// void Thing::inlineMethodThatLogs() const
949/// {
950/// BALL_LOG_TRACE << "log to PCKG.THING";
951/// }
952///
953/// } // close namespace pckg
954/// @endcode
955/// Now, we define the `outOfLineMethodThatLogs` method within the `.cpp` file.
956/// On each invocation, this method logs one record using `BALL_LOG_TRACE`. It
957/// logs to the "PCKG.THING" class-scope category if `useClassCategory` is
958/// `true`, and logs to the "X.Y.Z" block-scope category otherwise:
959/// @code
960/// // pckg_thing.cpp
961/// namespace pckg {
962///
963/// // ...
964///
965/// // MANIPULATORS
966/// void Thing::outOfLineMethodThatLogs(bool useClassCategory)
967/// {
968/// if (useClassCategory) {
969/// BALL_LOG_TRACE << "log to PCKG.THING";
970/// }
971/// else {
972/// BALL_LOG_SET_CATEGORY("X.Y.Z");
973/// BALL_LOG_TRACE << "log to X.Y.Z";
974/// }
975/// }
976///
977/// } // close namespace pckg
978/// @endcode
979/// Finally, note that both block-scope and class-scope categories can be logged
980/// to within the same block. For example, the following block within a `Thing`
981/// method would first log to "PCKG.THING" then log to "X.Y.Z":
982/// @code
983/// {
984/// BALL_LOG_TRACE << "log to PCKG.THING";
985///
986/// BALL_LOG_SET_CATEGORY("X.Y.Z");
987///
988/// BALL_LOG_TRACE << "log to X.Y.Z";
989/// }
990/// @endcode
991/// @}
992/** @} */
993/** @} */
994
995/** @addtogroup bal
996 * @{
997 */
998/** @addtogroup ball
999 * @{
1000 */
1001/** @addtogroup ball_log
1002 * @{
1003 */
1004
1005#include <balscm_version.h>
1006
1007#include <ball_category.h>
1008#include <ball_categorymanager.h>
1009#include <ball_loggermanager.h>
1010#include <ball_severity.h>
1011
1012#include <bslma_managedptr.h>
1013
1014#include <bsls_annotation.h>
1015#include <bsls_keyword.h>
1016#include <bsls_performancehint.h>
1017#include <bsls_platform.h>
1018
1019#include <bsl_ostream.h>
1020
1021#include <bslmt_mutex.h>
1022
1023 // =========================
1024 // Logging Macro Definitions
1025 // =========================
1026
1027#define BALL_LOG_CATEGORY \
1028 (ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER)->category())
1029
1030#define BALL_LOG_THRESHOLD \
1031 (ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER)->threshold())
1032
1033#define BALL_LOG_RECORD (ball_log_lOg_StReAm.record())
1034
1035#define BALL_LOG_OUTPUT_STREAM (ball_log_lOg_StReAm.stream())
1036
1037 // ===========================
1038 // Block-Scope Category Macros
1039 // ===========================
1040
1041#define BALL_LOG_SET_CATEGORY(CATEGORY) \
1042 static BloombergLP::ball::CategoryHolder BALL_LOG_CATEGORYHOLDER = { \
1043 { BloombergLP::ball::CategoryHolder::e_UNINITIALIZED_CATEGORY }, \
1044 { 0 }, { 0 } \
1045 }; \
1046 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!BALL_LOG_CATEGORY)) { \
1047 BSLS_PERFORMANCEHINT_UNLIKELY_HINT; \
1048 BloombergLP::ball::Log::setCategory(&BALL_LOG_CATEGORYHOLDER, \
1049 CATEGORY); \
1050 }
1051
1052#define BALL_LOG_SET_CATEGORY_HIERARCHICALLY(CATEGORY) \
1053 static BloombergLP::ball::CategoryHolder BALL_LOG_CATEGORYHOLDER = { \
1054 { BloombergLP::ball::CategoryHolder::e_UNINITIALIZED_CATEGORY }, \
1055 { 0 }, { 0 } \
1056 }; \
1057 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!BALL_LOG_CATEGORY)) { \
1058 BSLS_PERFORMANCEHINT_UNLIKELY_HINT; \
1059 BloombergLP::ball::Log::setCategoryHierarchically( \
1060 &BALL_LOG_CATEGORYHOLDER, \
1061 CATEGORY); \
1062 }
1063
1064#define BALL_LOG_SET_DYNAMIC_CATEGORY(CATEGORY) \
1065 const BloombergLP::ball::Category *BALL_LOG_DYNAMIC_CATEGORY = \
1066 BloombergLP::ball::Log::setCategory(CATEGORY); \
1067 BloombergLP::ball::CategoryHolder BALL_LOG_CATEGORYHOLDER = { \
1068 { BloombergLP::ball::CategoryHolder::e_DYNAMIC_CATEGORY }, \
1069 { const_cast<BloombergLP::ball::Category *>( \
1070 BALL_LOG_DYNAMIC_CATEGORY) }, \
1071 { 0 } \
1072 };
1073
1074#define BALL_LOG_SET_DYNAMIC_CATEGORY_HIERARCHICALLY(CATEGORY) \
1075 const BloombergLP::ball::Category *BALL_LOG_DYNAMIC_CATEGORY = \
1076 BloombergLP::ball::Log::setCategoryHierarchically(CATEGORY); \
1077 BloombergLP::ball::CategoryHolder BALL_LOG_CATEGORYHOLDER = { \
1078 { BloombergLP::ball::CategoryHolder::e_DYNAMIC_CATEGORY }, \
1079 { const_cast<BloombergLP::ball::Category *>( \
1080 BALL_LOG_DYNAMIC_CATEGORY) }, \
1081 { 0 } \
1082 };
1083
1084 // ===========================
1085 // Class-Scope Category Macros
1086 // ===========================
1087
1088#define BALL_LOG_SET_CLASS_CATEGORY(CATEGORY) \
1089 static \
1090 const BloombergLP::ball::CategoryHolder *ball_log_getCategoryHolder( \
1091 const BloombergLP::ball::CategoryHolder& categoryHolder) \
1092 { \
1093 return &categoryHolder; \
1094 } \
1095 static \
1096 const BloombergLP::ball::CategoryHolder *ball_log_getCategoryHolder(int) \
1097 { \
1098 static BloombergLP::ball::CategoryHolder holder = { \
1099 { BloombergLP::ball::CategoryHolder::e_UNINITIALIZED_CATEGORY }, \
1100 { 0 }, { 0 } \
1101 }; \
1102 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!holder.category())) { \
1103 BSLS_PERFORMANCEHINT_UNLIKELY_HINT; \
1104 BloombergLP::ball::Log::setCategory(&holder, CATEGORY); \
1105 } \
1106 return &holder; \
1107 } \
1108 enum { BALL_LOG_CATEGORYHOLDER = 0 }
1109
1110#define BALL_LOG_SET_CLASS_CATEGORY_HIERARCHICALLY(CATEGORY) \
1111 static \
1112 const BloombergLP::ball::CategoryHolder *ball_log_getCategoryHolder( \
1113 const BloombergLP::ball::CategoryHolder& categoryHolder) \
1114 { \
1115 return &categoryHolder; \
1116 } \
1117 static \
1118 const BloombergLP::ball::CategoryHolder *ball_log_getCategoryHolder(int) \
1119 { \
1120 static BloombergLP::ball::CategoryHolder holder = { \
1121 { BloombergLP::ball::CategoryHolder::e_UNINITIALIZED_CATEGORY }, \
1122 { 0 }, { 0 } \
1123 }; \
1124 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!holder.category())) { \
1125 BSLS_PERFORMANCEHINT_UNLIKELY_HINT; \
1126 BloombergLP::ball::Log::setCategoryHierarchically(&holder, \
1127 CATEGORY); \
1128 } \
1129 return &holder; \
1130 } \
1131 enum { BALL_LOG_CATEGORYHOLDER = 0 }
1132
1133 // ===============================
1134 // Namespace-Scope Category Macros
1135 // ===============================
1136
1137#define BALL_LOG_SET_NAMESPACE_CATEGORY(CATEGORY) \
1138namespace { \
1139 static \
1140 const BloombergLP::ball::CategoryHolder *ball_log_getCategoryHolder(int) \
1141 { \
1142 static BloombergLP::ball::CategoryHolder holder = { \
1143 { BloombergLP::ball::CategoryHolder::e_UNINITIALIZED_CATEGORY }, \
1144 { 0 }, { 0 } \
1145 }; \
1146 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!holder.category())) { \
1147 BSLS_PERFORMANCEHINT_UNLIKELY_HINT; \
1148 BloombergLP::ball::Log::setCategory(&holder, CATEGORY); \
1149 } \
1150 return &holder; \
1151 } \
1152 enum { BALL_LOG_CATEGORYHOLDER = 0 }; \
1153}
1154
1155#define BALL_LOG_SET_NAMESPACE_CATEGORY_HIERARCHICALLY(CATEGORY) \
1156namespace { \
1157 static \
1158 const BloombergLP::ball::CategoryHolder *ball_log_getCategoryHolder(int) \
1159 { \
1160 static BloombergLP::ball::CategoryHolder holder = { \
1161 { BloombergLP::ball::CategoryHolder::e_UNINITIALIZED_CATEGORY }, \
1162 { 0 }, { 0 } \
1163 }; \
1164 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!holder.category())) { \
1165 BSLS_PERFORMANCEHINT_UNLIKELY_HINT; \
1166 BloombergLP::ball::Log::setCategoryHierarchically(&holder, \
1167 CATEGORY); \
1168 } \
1169 return &holder; \
1170 } \
1171 enum { BALL_LOG_CATEGORYHOLDER = 0 }; \
1172}
1173
1174 // ====================================
1175 // Implementation Details: Do *NOT* Use
1176 // ====================================
1177
1178// BALL_LOG_STREAM_CONST_IMP requires its argument to be a compile-time
1179// constant.
1180
1181#define BALL_LOG_STREAM_CONST_IMP(SEVERITY) \
1182for (const BloombergLP::ball::CategoryHolder *ball_log_cAtEgOrYhOlDeR = \
1183 BloombergLP::ball::Log::categoryHolderIfEnabled<(SEVERITY)>( \
1184 ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER)); \
1185 ball_log_cAtEgOrYhOlDeR; \
1186 ) \
1187for (BloombergLP::ball::Log_Stream ball_log_lOg_StReAm( \
1188 ball_log_cAtEgOrYhOlDeR->category(), \
1189 __FILE__, \
1190 __LINE__, \
1191 (SEVERITY)); \
1192 ball_log_cAtEgOrYhOlDeR; \
1193 ball_log_cAtEgOrYhOlDeR = 0)
1194
1195// BALL_LOG_STREAM_IMP allows its argument to be calculated at run-time, at a
1196// cost in performance.
1197
1198#define BALL_LOG_STREAM_IMP(SEVERITY) \
1199for (const BloombergLP::ball::CategoryHolder *ball_log_cAtEgOrYhOlDeR = \
1200 ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER); \
1201 ball_log_cAtEgOrYhOlDeR \
1202 && ball_log_cAtEgOrYhOlDeR->threshold() >= (SEVERITY) \
1203 && BloombergLP::ball::Log::isCategoryEnabled(ball_log_cAtEgOrYhOlDeR, \
1204 (SEVERITY)); \
1205 ) \
1206for (BloombergLP::ball::Log_Stream ball_log_lOg_StReAm( \
1207 ball_log_cAtEgOrYhOlDeR->category(), \
1208 __FILE__, \
1209 __LINE__, \
1210 (SEVERITY)); \
1211 ball_log_cAtEgOrYhOlDeR; \
1212 ball_log_cAtEgOrYhOlDeR = 0)
1213
1214 // =======================
1215 // C++ stream-based macros
1216 // =======================
1217
1218#define BALL_LOG_STREAM(SEVERITY) \
1219 BALL_LOG_STREAM_IMP((SEVERITY)) BALL_LOG_OUTPUT_STREAM
1220
1221#define BALL_LOG_TRACE \
1222 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_TRACE) \
1223 BALL_LOG_OUTPUT_STREAM
1224
1225#define BALL_LOG_DEBUG \
1226 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_DEBUG) \
1227 BALL_LOG_OUTPUT_STREAM
1228
1229#define BALL_LOG_INFO \
1230 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_INFO) \
1231 BALL_LOG_OUTPUT_STREAM
1232
1233#define BALL_LOG_WARN \
1234 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_WARN) \
1235 BALL_LOG_OUTPUT_STREAM
1236
1237#define BALL_LOG_ERROR \
1238 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_ERROR) \
1239 BALL_LOG_OUTPUT_STREAM
1240
1241#define BALL_LOG_FATAL \
1242 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_FATAL) \
1243 BALL_LOG_OUTPUT_STREAM
1244
1245#define BALL_LOG_STREAM_BLOCK(SEVERITY) BALL_LOG_STREAM_IMP((SEVERITY))
1246
1247#define BALL_LOG_TRACE_BLOCK \
1248 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_TRACE)
1249
1250#define BALL_LOG_DEBUG_BLOCK \
1251 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_DEBUG)
1252
1253#define BALL_LOG_INFO_BLOCK \
1254 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_INFO)
1255
1256#define BALL_LOG_WARN_BLOCK \
1257 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_WARN)
1258
1259#define BALL_LOG_ERROR_BLOCK \
1260 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_ERROR)
1261
1262#define BALL_LOG_FATAL_BLOCK \
1263 BALL_LOG_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_FATAL)
1264
1265#define BALL_LOG_END ""
1266
1267 // ====================================
1268 // Implementation Details: Do *NOT* Use
1269 // ====================================
1270
1271// BALL_LOGCB_STREAM_CONST_IMP requires its first argument to be a compile-time
1272// constant.
1273
1274#define BALL_LOGCB_STREAM_CONST_IMP(SEVERITY, CALLBACK) \
1275for (const BloombergLP::ball::CategoryHolder *ball_log_cAtEgOrYhOlDeR = \
1276 BloombergLP::ball::Log::categoryHolderIfEnabled<(SEVERITY)>( \
1277 ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER)); \
1278 ball_log_cAtEgOrYhOlDeR; \
1279 ) \
1280for (BloombergLP::ball::Log_Stream ball_log_lOg_StReAm( \
1281 ball_log_cAtEgOrYhOlDeR->category(), \
1282 __FILE__, \
1283 __LINE__, \
1284 (SEVERITY)); \
1285 ball_log_cAtEgOrYhOlDeR \
1286 && (CALLBACK(&BALL_LOG_RECORD->customFields()), true); \
1287 ball_log_cAtEgOrYhOlDeR = 0)
1288
1289// BALL_LOGCB_STREAM_IMP allows its first argument to be calculated at
1290// run-time, at a cost in performance.
1291
1292#define BALL_LOGCB_STREAM_IMP(SEVERITY, CALLBACK) \
1293for (const BloombergLP::ball::CategoryHolder *ball_log_cAtEgOrYhOlDeR = \
1294 ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER); \
1295 ball_log_cAtEgOrYhOlDeR \
1296 && ball_log_cAtEgOrYhOlDeR->threshold() >= (SEVERITY) \
1297 && BloombergLP::ball::Log::isCategoryEnabled(ball_log_cAtEgOrYhOlDeR, \
1298 (SEVERITY)); \
1299 ) \
1300for (BloombergLP::ball::Log_Stream ball_log_lOg_StReAm( \
1301 ball_log_cAtEgOrYhOlDeR->category(), \
1302 __FILE__, \
1303 __LINE__, \
1304 (SEVERITY)); \
1305 ball_log_cAtEgOrYhOlDeR \
1306 && (CALLBACK(&BALL_LOG_RECORD->customFields()), true); \
1307 ball_log_cAtEgOrYhOlDeR = 0)
1308
1309 // ========================================
1310 // C++ stream-based macros using a callback
1311 // ========================================
1312
1313#define BALL_LOGCB_STREAM(BALL_SEVERITY, CALLBACK) \
1314 BALL_LOGCB_STREAM_IMP((BALL_SEVERITY), (CALLBACK)) BALL_LOG_OUTPUT_STREAM
1315
1316#define BALL_LOGCB_TRACE(CALLBACK) \
1317 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_TRACE, \
1318 (CALLBACK)) \
1319 BALL_LOG_OUTPUT_STREAM
1320
1321#define BALL_LOGCB_DEBUG(CALLBACK) \
1322 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_DEBUG, \
1323 (CALLBACK)) \
1324 BALL_LOG_OUTPUT_STREAM
1325
1326#define BALL_LOGCB_INFO(CALLBACK) \
1327 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_INFO, \
1328 (CALLBACK)) \
1329 BALL_LOG_OUTPUT_STREAM
1330
1331#define BALL_LOGCB_WARN(CALLBACK) \
1332 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_WARN, \
1333 (CALLBACK)) \
1334 BALL_LOG_OUTPUT_STREAM
1335
1336#define BALL_LOGCB_ERROR(CALLBACK) \
1337 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_ERROR, \
1338 (CALLBACK)) \
1339 BALL_LOG_OUTPUT_STREAM
1340
1341#define BALL_LOGCB_FATAL(CALLBACK) \
1342 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_FATAL, \
1343 (CALLBACK)) \
1344 BALL_LOG_OUTPUT_STREAM
1345
1346#define BALL_LOGCB_STREAM_BLOCK(BALL_SEVERITY, CALLBACK) \
1347 BALL_LOGCB_STREAM_IMP((BALL_SEVERITY), (CALLBACK))
1348
1349#define BALL_LOGCB_TRACE_BLOCK(CALLBACK) \
1350 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_TRACE, \
1351 (CALLBACK))
1352
1353#define BALL_LOGCB_DEBUG_BLOCK(CALLBACK) \
1354 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_DEBUG, \
1355 (CALLBACK))
1356
1357#define BALL_LOGCB_INFO_BLOCK(CALLBACK) \
1358 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_INFO, \
1359 (CALLBACK))
1360
1361#define BALL_LOGCB_WARN_BLOCK(CALLBACK) \
1362 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_WARN, \
1363 (CALLBACK))
1364
1365#define BALL_LOGCB_ERROR_BLOCK(CALLBACK) \
1366 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_ERROR, \
1367 (CALLBACK))
1368
1369#define BALL_LOGCB_FATAL_BLOCK(CALLBACK) \
1370 BALL_LOGCB_STREAM_CONST_IMP(BloombergLP::ball::Severity::e_FATAL, \
1371 (CALLBACK))
1372
1373#define BALL_LOGCB_END ""
1374
1375 // ====================================
1376 // Implementation Details: Do *NOT* Use
1377 // ====================================
1378
1379// BALL_LOGVA_CONST_IMP requires its first argument to be a compile-time
1380// constant, while all the others may be variables.
1381
1382#define BALL_LOGVA_CONST_IMP(SEVERITY, ...) \
1383do { \
1384 if (const BloombergLP::ball::CategoryHolder *ball_log_cAtEgOrYhOlDeR = \
1385 BloombergLP::ball::Log::categoryHolderIfEnabled<(SEVERITY)>( \
1386 ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER))) { \
1387 BloombergLP::ball::Log_Formatter ball_log_fOrMaTtEr( \
1388 ball_log_cAtEgOrYhOlDeR->category(), \
1389 __FILE__, \
1390 __LINE__, \
1391 (SEVERITY)); \
1392 BloombergLP::ball::Log::format(ball_log_fOrMaTtEr.messageBuffer(), \
1393 ball_log_fOrMaTtEr.messageBufferLen(), \
1394 __VA_ARGS__); \
1395 } \
1396} while(0)
1397
1398 // =====================
1399 // 'printf'-style macros
1400 // =====================
1401
1402// BALL_LOGVA allows all its arguments to be calculated at run-time, at a cost
1403// in performance.
1404
1405#define BALL_LOGVA(SEVERITY, ...) \
1406do { \
1407 const BloombergLP::ball::CategoryHolder *ball_log_cAtEgOrYhOlDeR = \
1408 ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER); \
1409 if (ball_log_cAtEgOrYhOlDeR->threshold() >= (SEVERITY) && \
1410 BloombergLP::ball::Log::isCategoryEnabled(ball_log_cAtEgOrYhOlDeR, \
1411 (SEVERITY))) { \
1412 BloombergLP::ball::Log_Formatter ball_log_fOrMaTtEr( \
1413 ball_log_cAtEgOrYhOlDeR->category(), \
1414 __FILE__, \
1415 __LINE__, \
1416 (SEVERITY)); \
1417 BloombergLP::ball::Log::format(ball_log_fOrMaTtEr.messageBuffer(), \
1418 ball_log_fOrMaTtEr.messageBufferLen(), \
1419 __VA_ARGS__); \
1420 } \
1421} while(0)
1422
1423#define BALL_LOGVA_TRACE(...) \
1424 BALL_LOGVA_CONST_IMP(BloombergLP::ball::Severity::e_TRACE, __VA_ARGS__)
1425
1426#define BALL_LOGVA_DEBUG(...) \
1427 BALL_LOGVA_CONST_IMP(BloombergLP::ball::Severity::e_DEBUG, __VA_ARGS__)
1428
1429#define BALL_LOGVA_INFO( ...) \
1430 BALL_LOGVA_CONST_IMP(BloombergLP::ball::Severity::e_INFO, __VA_ARGS__)
1431
1432#define BALL_LOGVA_WARN( ...) \
1433 BALL_LOGVA_CONST_IMP(BloombergLP::ball::Severity::e_WARN, __VA_ARGS__)
1434
1435#define BALL_LOGVA_ERROR(...) \
1436 BALL_LOGVA_CONST_IMP(BloombergLP::ball::Severity::e_ERROR, __VA_ARGS__)
1437
1438#define BALL_LOGVA_FATAL(...) \
1439 BALL_LOGVA_CONST_IMP(BloombergLP::ball::Severity::e_FATAL, __VA_ARGS__)
1440
1441 // ==============
1442 // Utility Macros
1443 // ==============
1444
1445#define BALL_LOG_IS_ENABLED(SEVERITY) \
1446 ((BALL_LOG_THRESHOLD >= (SEVERITY)) \
1447 && BloombergLP::ball::Log::isCategoryEnabled( \
1448 ball_log_getCategoryHolder(BALL_LOG_CATEGORYHOLDER), \
1449 (SEVERITY)))
1450
1451
1452
1453
1454namespace ball {
1455
1456// BDE_VERIFY pragma: push
1457// BDE_VERIFY pragma: -AQQ01
1458// BDE_VERIFY pragma: -AQS01
1459// BDE_VERIFY pragma: -FB01
1460// BDE_VERIFY pragma: -KS00
1461// BDE_VERIFY pragma: -TR04
1462// BDE_VERIFY pragma: -TR17
1463
1464 // =======================
1465 // CategoryHolder Accessor
1466 // =======================
1467
1468/// Return the address of the specified `categoryHolder`. Note that this
1469/// function facilitates consistent lookup of block-scope and class-scope
1470/// category holders (see "Logging Macro Reuse" in the "IMPLEMENTATION
1471/// NOTES" of the component implementation file for details).
1472inline
1473const BloombergLP::ball::CategoryHolder* ball_log_getCategoryHolder(
1474 const BloombergLP::ball::CategoryHolder& categoryHolder)
1475{
1476 return &categoryHolder;
1477}
1478
1479// BDE_VERIFY pragma: pop
1480
1481class Record;
1482
1483 // ==========
1484 // struct Log
1485 // ==========
1486
1487/// This `struct` provides a namespace for a suite of utility functions that
1488/// simplify usage of the @ref ball_loggermanager component. The direct use
1489/// of these utility functions is *strongly* discouraged.
1490struct Log {
1491
1492 // CLASS METHODS
1493
1494 /// Fill the specified `buffer` with at most the specified `numBytes`
1495 /// characters produced by formatting the variable argument list
1496 /// according to the specified `printf`-style `format` argument; return
1497 /// the number of characters in the resulting formatted string. The
1498 /// last character placed into `buffer` is always a null terminator
1499 /// (leaving at most `numBytes - 1` bytes of formatted data). If
1500 /// `numBytes` is insufficient for the entire formatted string, this
1501 /// method fills `buffer` with the initial `numBytes - 1` bytes of
1502 /// formatted data followed by a null terminator and returns -1. Note
1503 /// that with the exception of the return value, the behavior of this
1504 /// function exactly matches that of the C99 function `snprintf`. Also
1505 /// note that `snprintf` is not part of standard C++-98, so its
1506 /// functionality is provided here.
1507 static int format(char *buffer,
1508 bsl::size_t numBytes,
1509 const char *format, ...) BSLS_ANNOTATION_PRINTF(3, 4);
1510
1511 /// Return the address of a modifiable record having the specified
1512 /// `fileName` and `lineNumber` attributes. The memory for the record
1513 /// will be supplied by the allocator held by the logger manager
1514 /// singleton if the specified `category` is non-null, or by the
1515 /// currently installed default allocator otherwise. The behavior is
1516 /// undefined unless the logger manager singleton is initialized when
1517 /// `category` is non-null. Note that the returned `Record` must
1518 /// subsequently be supplied to a call to the 3-argument `logMessage`
1519 /// method.
1520 static Record *getRecord(const Category *category,
1521 const char *fileName,
1522 int lineNumber);
1523
1524 /// Log a record containing the specified `message` text, `fileName`,
1525 /// `lineNumber`, `severity`, and the name of the specified `category`.
1526 /// (See the component-level documentation of @ref ball_record for more
1527 /// information on the additional fields that are logged.) Store the
1528 /// record in the buffer held by the logger if `severity` is at least
1529 /// as severe as the current "Record" threshold level of `category`.
1530 /// Pass the record directly to the registered observer if `severity`
1531 /// is at least as severe as the current "Pass" threshold level of
1532 /// `category`. Publish the entire contents of the buffer of the
1533 /// logger if `severity` is at least as severe as the current "Trigger"
1534 /// threshold level of `category`. Publish the entire contents of all
1535 /// buffers of all loggers if `severity` is at least as severe as the
1536 /// current "Trigger-All" threshold level of `category` (i.e., via the
1537 /// callback supplied at construction of the logger manager singleton).
1538 /// This method has no effect if `category` is 0 or `severity` is less
1539 /// severe than each of the threshold levels of `category`. The
1540 /// behavior is undefined unless `severity` is in the range `[1 .. 255]`
1541 /// and the logger manager singleton is initialized when `category` is
1542 /// non-null.
1543 static void logMessage(const Category *category,
1544 int severity,
1545 const char *fileName,
1546 int lineNumber,
1547 const char *message);
1548
1549 /// Log the specified `record` after setting its category attribute to
1550 /// the specified `category` and its severity attribute to the specified
1551 /// `severity`. (See the component-level documentation of @ref ball_record
1552 /// for more information on the fields that are logged.) Store the
1553 /// record in the buffer held by the logger if `severity` is at least
1554 /// as severe as the current "Record" threshold level of `category`.
1555 /// Pass the record directly to the registered observer if `severity`
1556 /// is at least as severe as the current "Pass" threshold level of
1557 /// `category`. Publish the entire contents of the buffer of the
1558 /// logger if `severity` is at least as severe as the current "Trigger"
1559 /// threshold level of `category`. Publish the entire contents of all
1560 /// buffers of all loggers if `severity` is at least as severe as the
1561 /// current "Trigger-All" threshold level of `category` (i.e., via the
1562 /// callback supplied at construction of the logger manager singleton).
1563 /// Finally, dispose of `record`. This method has no effect (other than
1564 /// disposing of `record`) if `severity` is less severe than each of the
1565 /// threshold levels of `category`. The behavior is undefined unless
1566 /// `severity` is in the range `[1 .. 255]`, `record` was obtained by a
1567 /// call to `Log::getRecord`, and, if `category` is not 0, the logger
1568 /// manager singleton is initialized. Note that `record` will be
1569 /// invalid after this method returns.
1570 static void logMessage(const Category *category,
1571 int severity,
1572 Record *record);
1573
1574 /// Block until access to the buffer used for formatting messages in
1575 /// this thread of execution is available. Return the address of the
1576 /// modifiable buffer to which this thread of execution has exclusive
1577 /// access, load the address of the mutex that protects the buffer into
1578 /// the specified `*mutex` address, and load the size (in bytes) of the
1579 /// buffer into the specified `bufferSize` address. The address remains
1580 /// valid, and the buffer remains locked by this thread of execution,
1581 /// until the `Log::releaseMessageBuffer` method is called. The
1582 /// behavior is undefined if this thread of execution currently holds a
1583 /// lock on the buffer. Note that the buffer is intended to be used
1584 /// *only* for formatting log messages immediately before a call to
1585 /// `Log::logMessage`; other use may adversely affect performance for
1586 /// the entire program.
1587 static char *obtainMessageBuffer(bslmt::Mutex **mutex,
1588 int *bufferSize);
1589
1590 /// Unlock the specified `mutex` that guards the buffer used for
1591 /// formatting messages in this thread of execution. The behavior is
1592 /// undefined unless `mutex` was obtained by a call to
1593 /// `Log::obtainMessageBuffer` and has not yet been unlocked.
1594 static void releaseMessageBuffer(bslmt::Mutex *mutex);
1595
1596 /// Return a managed pointer that refers to the memory block to which
1597 /// this thread of execution has exclusive access and load the size (in
1598 /// bytes) of this buffer into the specified `bufferSize` address. Note
1599 /// that this method is intended for *internal* *use* only.
1600 static bslma::ManagedPtr<char> obtainMessageBuffer(int *bufferSize);
1601
1602 /// Return from the logger manager singleton's category registry the
1603 /// address of the non-modifiable category having the specified
1604 /// `categoryName` if such a category exists, or if a new category
1605 /// having `categoryName` can be added to the registry (i.e., if the
1606 /// registry has sufficient capacity to accommodate new entries);
1607 /// otherwise, return the address of the non-modifiable *Default*
1608 /// *Category*. Return 0 if the logger manager singleton is not
1609 /// initialized.
1610 static const Category *setCategory(const char *categoryName);
1611
1612 /// Return the specified `categoryHolder` if the severity warrants
1613 /// logging according to the specified `t_SEVERITY` and
1614 /// `categoryHolder`, and 0 otherwise.
1615 template <int t_SEVERITY>
1617 const CategoryHolder *categoryHolder);
1618
1619 /// Load into the specified `categoryHolder` the address of the
1620 /// non-modifiable category having the specified `categoryName` if such
1621 /// a category exists, or if a new category having `categoryName` can
1622 /// be added to the registry (i.e., if the registry has sufficient
1623 /// capacity to accommodate new entries); otherwise, load the address of
1624 /// the non-modifiable *Default* *Category*. Also load into
1625 /// `categoryHolder` the maximum threshold level of the category
1626 /// ultimately loaded into `categoryHolder`. This method has no effect
1627 /// if the logger manager singleton is not initialized.
1628 static void setCategory(CategoryHolder *categoryHolder,
1629 const char *categoryName);
1630
1631 /// Return from the logger manager singleton's category registry the
1632 /// address of the non-modifiable category having the specified
1633 /// `categoryName`, or, if no such category exists, add a new category
1634 /// having `categoryName` to the registry if possible (i.e., if the
1635 /// registry has sufficient capacity to accommodate new entries);
1636 /// otherwise, return the address of the non-modifiable *Default*
1637 /// *Category*. If the logger manager singleton is not initialized,
1638 /// return 0 with no effect. If a new category is created, it will have
1639 /// the same threshold levels as the category in the logger manager
1640 /// singleton whose name is the longest non-empty prefix of
1641 /// `categoryName` if such a category exists, and the threshold levels
1642 /// will be set as if `setCategory` had been called otherwise.
1643 static const Category *setCategoryHierarchically(const char *categoryName);
1644
1645 /// Return from the logger manager singleton's category registry the
1646 /// address of the non-modifiable category having the specified
1647 /// `categoryName`, or, if no such category exists, add a new category
1648 /// having `categoryName` to the registry if possible (i.e., if the
1649 /// registry has sufficient capacity to accommodate new entries);
1650 /// otherwise, return the address of the non-modifiable *Default*
1651 /// *Category*. If the logger manager singleton is not initialized,
1652 /// return 0 with no effect. If a new category is created, it will have
1653 /// the same threshold levels as the category in the logger manager
1654 /// singleton whose name is the longest non-empty prefix of
1655 /// `categoryName` if such a category exists, and the threshold levels
1656 /// will be set as if `setCategory` had been called otherwise. If the
1657 /// specified `categoryHolder` is non-zero, load it with the address of
1658 /// the returned category and the maximum threshold level of that
1659 /// category, and link `categoryHolder` to the other holders (if any)
1660 /// that currently reference the category. Note that this method has
1661 /// the same effect on the logger manager singleton's category registry
1662 /// as the one-argument `setCategoryHierarchically` regardless of
1663 /// whether `0 == categoryHolder`.
1665 CategoryHolder *categoryHolder,
1666 const char *categoryName);
1667
1668 /// Return `true` if logging to the category associated with the
1669 /// specified `categoryHolder` at the specified `severity` is enabled,
1670 /// or if `Severity::e_WARN >= severity` and the logger manager
1671 /// singleton is not initialized; return `false` otherwise.
1672 static bool isCategoryEnabled(const CategoryHolder *categoryHolder,
1673 int severity);
1674};
1675
1676 // ================
1677 // class Log_Stream
1678 // ================
1679
1680/// This class provides an aggregate of several objects relevant to the
1681/// logging of a message via the C++ stream-based macros:
1682/// @code
1683/// - record to be logged
1684/// - category to which to log the record
1685/// - severity at which to log the record
1686/// - stream to which the user log message is put
1687/// @endcode
1688/// As a side-effect of creating an object of this class, the record and
1689/// stream are also constructed. As a side-effect of destroying the
1690/// object, the record is logged.
1691///
1692/// This class should *not* be used directly by client code. It is an
1693/// implementation detail of the macros provided by this component.
1694///
1695/// See @ref ball_log
1697
1698 // DATA
1699 const Category *d_category_p; // category to which record is logged
1700 // (held, not owned)
1701
1702 Record *d_record_p; // logged record (held, not owned)
1703
1704 const int d_severity; // severity at which record is logged
1705
1706 private:
1707 // NOT IMPLEMENTED
1708 Log_Stream(const Log_Stream&);
1709 Log_Stream& operator=(const Log_Stream&);
1710
1711 public:
1712 // CREATORS
1713
1714 /// Create a logging stream that holds (1) the specified `category` and
1715 /// `severity`, (2) a record that is created from the specified
1716 /// `fileName` and `lineNumber`, and (3) an `bsl::ostream` to which the
1717 /// log message is put.
1718 Log_Stream(const Category *category,
1719 const char *fileName,
1720 int lineNumber,
1721 int severity);
1722
1723 /// Log the record held by this logging stream to the held category (as
1724 /// returned by `category`) at the held severity (as returned by
1725 /// `severity`) and destroy this logging stream.
1727
1728 // MANIPULATORS
1729
1730 /// Return the address of the modifiable log record held by this logging
1731 /// stream. The address remains valid until this logging stream is
1732 /// destroyed.
1733 Record *record();
1734
1735 /// Return a reference to the modifiable stream held by this logging
1736 /// stream. The reference remains valid until this logging stream is
1737 /// destroyed.
1738 bsl::ostream& stream();
1739
1740 // ACCESSORS
1741
1742 /// Return the address of the non-modifiable category held by this
1743 /// logging stream.
1744 const Category *category() const;
1745
1746 /// Return the address of the non-modifiable log record held by this
1747 /// logging stream. The address remains valid until this logging stream
1748 /// is destroyed.
1749 const Record *record() const;
1750
1751 /// Return the severity held by this logging stream.
1752 int severity() const;
1753};
1754
1755 // ===================
1756 // class Log_Formatter
1757 // ===================
1758
1759/// This class provides an aggregate of several objects relevant to the
1760/// logging of a message via the `printf`-style macros:
1761/// @code
1762/// - record to be logged
1763/// - category to which to log the record
1764/// - severity at which to log the record
1765/// - buffer in which the user log message is formatted
1766/// @endcode
1767/// As a side-effect of creating an object of this class, the record is
1768/// constructed, and the buffer is obtained. As a side-effect of destroying
1769/// the object, the record is formatted, using the buffer, and logged.
1770///
1771/// This class should *not* be used directly by client code. It is an
1772/// implementation detail of the macros provided by this component.
1773///
1774/// See @ref ball_log
1776
1777 // DATA
1778 const Category *d_category_p; // category to which record is
1779 // logged (held, not owned)
1780
1781 Record *d_record_p; // logged record (held, not owned)
1782
1783 const int d_severity; // severity at which record is
1784 // logged
1785
1786 int d_bufferLen; // length of buffer
1787
1788 bslma::ManagedPtr<char> d_buffer; // buffer for formatted user log
1789 // message
1790
1791 private:
1792 // NOT IMPLEMENTED
1794 Log_Formatter& operator=(const Log_Formatter&);
1795
1796 public:
1797 // CREATORS
1798
1799 /// Create a logging formatter that holds (1) the specified `category`
1800 /// and `severity`, (2) a record that is created from the specified
1801 /// `fileName` and `lineNumber`, and (3) a buffer into which the log
1802 /// message is formatted.
1803 Log_Formatter(const Category *category,
1804 const char *fileName,
1805 int lineNumber,
1806 int severity);
1807
1808 /// Log the record held by this logging formatter to the held category
1809 /// (as returned by `category`) at the held severity (as returned by
1810 /// `severity`), and destroy this logging formatter.
1812
1813 // MANIPULATORS
1814
1815 /// Return the address of the modifiable buffer held by this logging
1816 /// formatter. The address remains valid until this logging formatter
1817 /// is destroyed.
1818 char *messageBuffer();
1819
1820 /// Return the address of the modifiable log record held by this logging
1821 /// formatter. The address remains valid until this logging formatter
1822 /// is destroyed.
1823 Record *record();
1824
1825 // ACCESSORS
1826
1827 /// Return the address of the non-modifiable category held by this
1828 /// logging formatter.
1829 const Category *category() const;
1830
1831 /// Return the length (in bytes) of the buffer held by this logging
1832 /// formatter.
1833 int messageBufferLen() const;
1834
1835 /// Return the address of the non-modifiable log record held by this
1836 /// logging formatter. The address remains valid until this logging
1837 /// formatter is destroyed.
1838 const Record *record() const;
1839
1840 /// Return the severity held by this logging formatter.
1841 int severity() const;
1842};
1843
1844// ============================================================================
1845// INLINE DEFINITIONS
1846// ============================================================================
1847
1848 // ----------
1849 // struct Log
1850 // ----------
1851
1852// CLASS METHODS
1853template <int t_SEVERITY>
1854inline
1856 const CategoryHolder *categoryHolder)
1857{
1858 // The following condition is calculated at compile time so has no run-time
1859 // cost. Code from the branch not taken will not be generated. Note that
1860 // we expect TRACE and DEBUG messages not to be logged and thus they are
1861 // marked with unlikely performance hints.
1862
1863 if (t_SEVERITY <= Severity::e_INFO) {
1864 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(categoryHolder->threshold() >=
1865 t_SEVERITY)) {
1867 Log::isCategoryEnabled(categoryHolder, t_SEVERITY))) {
1868 return categoryHolder; // RETURN
1869 }
1870 else {
1872 }
1873
1875 }
1876 }
1877 else {
1879 categoryHolder->threshold() >= t_SEVERITY)) {
1881
1883 Log::isCategoryEnabled(categoryHolder, t_SEVERITY))) {
1885
1886 return categoryHolder; // RETURN
1887 }
1888 }
1889 }
1890
1891 return 0;
1892}
1893
1894inline
1895const Category *Log::setCategoryHierarchically(const char *categoryName)
1896{
1897 return setCategoryHierarchically(0, categoryName);
1898}
1899
1900 // ----------------
1901 // class Log_Stream
1902 // ----------------
1903
1904// MANIPULATORS
1905inline
1907{
1908 return d_record_p;
1909}
1910
1911inline
1912bsl::ostream& Log_Stream::stream()
1913{
1914 return d_record_p->fixedFields().messageStream();
1915}
1916
1917// ACCESSORS
1918inline
1920{
1921 return d_category_p;
1922}
1923
1924inline
1926{
1927 return d_record_p;
1928}
1929
1930inline
1932{
1933 return d_severity;
1934}
1935
1936 // -------------------
1937 // class Log_Formatter
1938 // -------------------
1939
1940// MANIPULATORS
1941inline
1943{
1944 return d_buffer.get();
1945}
1946
1947inline
1949{
1950 return d_record_p;
1951}
1952
1953// ACCESSORS
1954inline
1956{
1957 return d_category_p;
1958}
1959
1960inline
1962{
1963 return d_bufferLen;
1964}
1965
1966inline
1968{
1969 return d_record_p;
1970}
1971
1972inline
1974{
1975 return d_severity;
1976}
1977
1978} // close package namespace
1979
1980
1981#endif
1982
1983// ----------------------------------------------------------------------------
1984// Copyright 2017 Bloomberg Finance L.P.
1985//
1986// Licensed under the Apache License, Version 2.0 (the "License");
1987// you may not use this file except in compliance with the License.
1988// You may obtain a copy of the License at
1989//
1990// http://www.apache.org/licenses/LICENSE-2.0
1991//
1992// Unless required by applicable law or agreed to in writing, software
1993// distributed under the License is distributed on an "AS IS" BASIS,
1994// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1995// See the License for the specific language governing permissions and
1996// limitations under the License.
1997// ----------------------------- END-OF-FILE ----------------------------------
1998
1999/** @} */
2000/** @} */
2001/** @} */
Definition ball_category.h:362
int threshold() const
Return the threshold level held by this holder.
Definition ball_category.h:616
Definition ball_category.h:184
Definition ball_log.h:1775
Record * record()
Definition ball_log.h:1948
char * messageBuffer()
Definition ball_log.h:1942
const Category * category() const
Definition ball_log.h:1955
int messageBufferLen() const
Definition ball_log.h:1961
Log_Formatter(const Category *category, const char *fileName, int lineNumber, int severity)
int severity() const
Return the severity held by this logging formatter.
Definition ball_log.h:1973
Definition ball_log.h:1696
bsl::ostream & stream()
Definition ball_log.h:1912
const Category * category() const
Definition ball_log.h:1919
~Log_Stream() BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(false)
Record * record()
Definition ball_log.h:1906
int severity() const
Return the severity held by this logging stream.
Definition ball_log.h:1931
Log_Stream(const Category *category, const char *fileName, int lineNumber, int severity)
bsl::ostream & messageStream()
Definition ball_recordattributes.h:538
Definition ball_record.h:178
RecordAttributes & fixedFields()
Return the modifiable fixed fields of this log record.
Definition ball_record.h:396
Definition bslma_managedptr.h:1182
#define BSLS_ANNOTATION_PRINTF(fmt, arg)
Definition bsls_annotation.h:353
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(...)
Definition bsls_keyword.h:634
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
#define BSLS_PERFORMANCEHINT_UNLIKELY_HINT
Definition bsls_performancehint.h:484
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition ball_administration.h:214
const BloombergLP::ball::CategoryHolder * ball_log_getCategoryHolder(const BloombergLP::ball::CategoryHolder &categoryHolder)
Definition ball_log.h:1473
Definition bdlb_printmethods.h:283
Definition balxml_encoderoptions.h:68
Definition bslmt_barrier.h:344
Definition ball_log.h:1490
static int static Record * getRecord(const Category *category, const char *fileName, int lineNumber)
static void releaseMessageBuffer(bslmt::Mutex *mutex)
static void logMessage(const Category *category, int severity, const char *fileName, int lineNumber, const char *message)
static const CategoryHolder * categoryHolderIfEnabled(const CategoryHolder *categoryHolder)
Definition ball_log.h:1855
static int format(char *buffer, bsl::size_t numBytes, const char *format,...) BSLS_ANNOTATION_PRINTF(3
static bool isCategoryEnabled(const CategoryHolder *categoryHolder, int severity)
static const Category * setCategory(const char *categoryName)
static char * obtainMessageBuffer(bslmt::Mutex **mutex, int *bufferSize)
static const Category * setCategoryHierarchically(const char *categoryName)
Definition ball_log.h:1895
@ e_INFO
Definition ball_severity.h:172