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