BDE 4.39.x Production Release
Loading...
Searching...
No Matches
balm.h
Go to the documentation of this file.
1/// @file balm.h
2///
3///
4/// @defgroup balm Package balm
5/// @brief Basic Application Library Metrics (balm)
6/// @addtogroup bal
7/// @{
8/// @addtogroup balm
9/// @{
10/// * <a href="#balm-purpose"> Purpose</a>
11/// * <a href="#balm-mnemonic"> Mnemonic </a>
12/// * <a href="#balm-description"> Description </a>
13/// * <a href="#balm-hierarchical-synopsis"> Hierarchical Synopsis </a>
14/// * <a href="#balm-component-synopsis"> Component Synopsis </a>
15/// * <a href="#balm-getting-started"> Getting Started </a>
16/// * <a href="#balm-features-overview"> Features Overview </a>
17/// * <a href="#balm-multi-threading"> Multi-Threading </a>
18/// * <a href="#balm-collecting-metrics"> Collecting Metrics </a>
19/// * <a href="#balm-choosing-between-ref-balm_metric-and-ref-balm_integermetric"> Choosing Between @ref balm_metric and @ref balm_integermetric </a>
20/// * <a href="#balm-choosing-between-metric-collection-macros-and-metric-collection-classes"> Choosing Between Metric Collection Macros and Metric Collection Classes </a>
21/// * <a href="#balm-creating-a-user-defined-collection-mechanism"> Creating a User Defined Collection Mechanism </a>
22/// * <a href="#balm-publishing-metrics"> Publishing Metrics </a>
23/// * <a href="#balm-periodically-publishing-metrics"> Periodically Publishing Metrics </a>
24/// * <a href="#balm-disabling-metric-categories"> Disabling Metric Categories </a>
25///
26/// # Purpose {#balm-purpose}
27/// Provide thread-safe collection and publishing of metrics.
28///
29/// # Mnemonic {#balm-mnemonic}
30/// Basic Application Library Metrics (balm)
31///
32/// # Description {#balm-description}
33/// The 'balm' package provides facilities for recording and
34/// publishing metric data.
35///
36/// Bloomberg internal software should also consider the GUTS telemetry API, which
37/// is integrated into Bloomberg infrastructure.
38///
39/// A "metric", in the context of this package, is a measured event. This package
40/// does *not* define what constitutes an event or what the associated measurement
41/// represents. For example, a metric could record the elapsed time of a function
42/// call (in which case the event is the function call, and the measured value is
43/// the elapsed time), or a metric could record the number of requests received by
44/// a service (in which case the event is the reception of a request, and the
45/// measured value is 1).
46///
47/// This package provides components for collecting and aggregating measurement
48/// values (see @ref balm_metric and @ref balm_metrics ). Those aggregated metric
49/// measurements are described by a metric record (see @ref balm_metricrecord ), which
50/// contains the identifier for the recorded metric, the number of times the event
51/// occurred, as well as the minimum, maximum, and total of the measured values.
52/// This package provides a protocol for publishing metric records (see
53/// @ref balm_publisher ) and an implementation of that protocol for publishing
54/// records to a stream (see 'balm_streampublisher). Finally this package
55/// provides a @ref balm_metricsmanager component to coordinate the collection and
56/// publication of metrics.
57///
58/// ## Hierarchical Synopsis {#balm-hierarchical-synopsis}
59///
60/// The 'balm' package currently has 22 components having 13 levels of physical
61/// dependency. The list below shows the hierarchical ordering of the components.
62/// The order of components within each level is not architecturally significant,
63/// just alphabetical.
64/// @code
65/// 13. balm_configurationutil
66///
67/// 12. balm_metrics
68///
69/// 11. balm_stopwatchscopedguard
70///
71/// 10. balm_bdlmmetricsadapter
72/// balm_integermetric
73/// balm_metric
74///
75/// 9. balm_defaultmetricsmanager
76/// balm_publicationscheduler
77///
78/// 8. balm_metricsmanager
79/// balm_streampublisher
80///
81/// 7. balm_collectorrepository
82/// balm_publisher
83///
84/// 6. balm_collector
85/// balm_integercollector
86/// balm_metricsample
87///
88/// 5. balm_metricrecord
89/// balm_metricregistry
90///
91/// 4. balm_metricid
92///
93/// 3. balm_metricdescription
94///
95/// 2. balm_metricformat
96///
97/// 1. balm_category
98/// balm_publicationtype
99/// @endcode
100///
101/// ## Component Synopsis {#balm-component-synopsis}
102///
103/// @ref balm_bdlmmetricsadapter :
104/// Provide a concrete instance of the `bdlm` metrics adapter.
105///
106/// @ref balm_category :
107/// Provide a representation of a metric category.
108///
109/// @ref balm_collector :
110/// Provide a container for collecting and aggregating metric values.
111///
112/// @ref balm_collectorrepository :
113/// Provide a repository for collectors.
114///
115/// @ref balm_configurationutil :
116/// Provide a namespace for metrics configuration utilities.
117///
118/// @ref balm_defaultmetricsmanager :
119/// Provide for a default instance of the metrics manager.
120///
121/// @ref balm_integercollector :
122/// Provide a container for collecting integral metric values.
123///
124/// @ref balm_integermetric :
125/// Provide helper classes for recording int metric values.
126///
127/// @ref balm_metric :
128/// Provide helper classes for recording metric values.
129///
130/// @ref balm_metricdescription :
131/// Provide a description for a metric.
132///
133/// @ref balm_metricformat :
134/// Provide a formatting specification for a metric.
135///
136/// @ref balm_metricid :
137/// Provide an identifier for a metric.
138///
139/// @ref balm_metricrecord :
140/// Provide an aggregated record of the value of a metric.
141///
142/// @ref balm_metricregistry :
143/// Provide a registry for metrics.
144///
145/// @ref balm_metrics :
146/// Provide a suite of operations for recording metric values.
147///
148/// @ref balm_metricsample :
149/// Provide a container for a sample of collected metric records.
150///
151/// @ref balm_metricsmanager :
152/// Provide a manager for recording and publishing metric data.
153///
154/// @ref balm_publicationscheduler :
155/// Provide a scheduler for publishing metrics.
156///
157/// @ref balm_publicationtype :
158/// Provide an enumeration of aggregate types used to publish metrics.
159///
160/// @ref balm_publisher :
161/// Provide a protocol to publish recorded metric values.
162///
163/// @ref balm_stopwatchscopedguard :
164/// Provide a scoped guard for recording elapsed time.
165///
166/// @ref balm_streampublisher :
167/// Provide a `balm::Publisher` implementation that writes to a stream.
168///
169/// ## Getting Started {#balm-getting-started}
170///
171/// The following section presents a simple example of collecting metrics. We
172/// create a trivial application that reads lines of text from standard input and
173/// counts the number of letters, words, and unique words in each line. The
174/// function 'processLine()' processes each line of text and records metrics for
175/// the number of times 'processLine()' has been called, the elapsed time for the
176/// calls to 'processLine()', the total character count, and the total word count.
177///
178/// Before we can collect metrics we must first create a 'balm_MetricsManager'
179/// object to manage their collection (and publication). We use the
180/// 'balm_DefaultMetricsManager', which is a singleton instance of the
181/// 'balm_MetricsManager' class. The default metrics manager is used by the
182/// collection macros that we will use to collect metrics (see @ref balm_metrics ).
183/// Note that the default metrics manager is intended to be created and destroyed
184/// by the *owner* of 'main'. A default metrics manager instance should be
185/// created during the initialization of an application (while the task has a
186/// single thread) and destroyed just prior to termination (when there is,
187/// similarly, a single thread).
188/// @code
189/// int main(int argc, const char *argv[])
190/// {
191/// @endcode
192/// We create a 'balm_DefaultMetricsManagerScopedGuard', which manages the
193/// lifetime of the default metrics manager (singleton) instance. At
194/// construction, we provide the scoped guard an output stream ('stdout') to which
195/// the @ref balm_publisher (created by the default metrics manager) will publish
196/// metrics.
197/// @code
198/// balm_DefaultMetricsManagerScopedGuard managerGuard(bdl::cout);
199/// @endcode
200/// We create a 'balm_PublicationScheduler' to periodically publish the metrics we
201/// have collected. A 'balm_PublicationScheduler' invokes 'publish()' on the
202/// supplied 'balm_MetricsManager' object according to the provided schedule.
203/// @code
204/// bcep_TimerEventScheduler eventScheduler;
205/// balm_PublicationScheduler publicationScheduler(
206/// balm_DefaultMetricsManager::instance(),
207/// &eventScheduler);
208/// @endcode
209/// To begin periodically publishing metrics we 'start' the event scheduler
210/// supplied to the 'balm_PublicationScheduler', and then set a simple schedule to
211/// publish all collected metrics every 30 seconds.
212/// @code
213/// eventScheduler.start();
214/// publicationScheduler.setDefaultSchedule(bsls::TimeInterval(30, 0));
215/// @endcode
216/// Finally we have our main "application" loop, which reads lines of text from
217/// the standard input (until "exit" is provided as input) and calls
218/// 'processLine()' for each line of input.
219/// @code
220/// while (true) {
221/// enum { BUFFER_SIZE = 1024 };
222/// char buffer[BUFFER_SIZE];
223/// if (!bdl::cin.getline(buffer, BUFFER_SIZE)) {
224/// break;
225/// }
226/// if (0 == bdl::strcmp(buffer, "exit")) {
227/// break;
228/// }
229/// processLine(buffer);
230/// }
231/// @endcode
232/// At the end of this lexical scope 'managerGuard' is destroyed, releasing the
233/// default 'balm_MetricsManager' instance.
234/// @code
235/// }
236/// @endcode
237/// Next we define the 'processLine()' function. The 'processLine()' function
238/// "processes" a line of text, and collects several metrics related to the
239/// function invocation.
240/// @code
241/// void processLine(const bdl::string& line)
242/// // Process the specified 'line' of text and write to standard output the
243/// // number of characters, words, and unique words in 'line'.
244/// {
245/// @endcode
246/// Increment the count of the number of calls to 'processLine()' and use the
247/// 'BALM_METRICS_TIME_BLOCK' macro (see @ref balm_metrics ) to collect the elapsed
248/// time of this function call. Note that all the metrics recorded by this
249/// function belong to the (arbitrarily chosen) category "Example".
250/// @code
251/// BALM_METRICS_INCREMENT("Example", "processLineCount");
252/// BALM_METRICS_TIME_BLOCK("Example",
253/// "processLineElapsedTime",
254/// balm_StopwatchScopedGuard::BALM_SECONDS);
255///
256/// int wordCount = 0;
257/// bdl::set<bdl::string> words;
258///
259/// bdl::string word;
260/// bdl::istringstream istream(line);
261/// while (istream >> word) {
262/// words.insert(word);
263/// ++wordCount;
264/// }
265///
266/// bdl::cout << "Characters: count: " << line.size()
267/// << "\tWord count: " << wordCount
268/// << "\tUnique word count: " << words.size() << bdl::endl;
269///
270/// @endcode
271/// Once we've "processed" the 'line', update the character count and word count
272/// metrics.
273/// @code
274/// BALM_METRICS_UPDATE("Example", "characterCount", line.size());
275/// BALM_METRICS_UPDATE("Example", "wordCount", wordCount);
276/// }
277/// @endcode
278/// We've now created our example application. A typical session with this
279/// application might look like (note that '>' indicates user input):
280/// @code
281/// >this contains 4 words
282/// Characters: count: 21 Word count: 4 Unique word count: 4
283/// >this sentence contains 5 words
284/// Characters: count: 30 Word count: 5 Unique word count: 5
285/// @endcode
286/// Every 30 seconds metrics will be reported to standard output. A typical
287/// publication of metrics would look like:
288/// @code
289/// 17FEB2009_15:29:20.792+0000 4 Records
290/// Elapsed Time: 30.0092s
291/// Example.processLineCount [ count = 2, total = 2, min = 1, max = 1 ]
292/// Example.processLineElapsedTime [ count = 2, total = 0.0007656,
293/// min = 0.00022736, max = 0.00053824 ]
294/// Example.characterCount [ count = 2, total = 51, min = 21, max = 30 ]
295/// Example.wordCount [ count = 2, total = 9, min = 4, max = 5 ]
296/// @endcode
297///
298/// ## Features Overview {#balm-features-overview}
299///
300/// This section provides a brief summary of the features of the 'balm'
301/// package - details can be found in the indicated components and later in this
302/// document.
303///
304/// * A protocol to provide pluggable publishing behavior. Users can define and
305/// register publishers with the metrics manager, which in turn defines the
306/// behavior of the "publish" operation (see @ref balm_publisher )
307///
308/// * A default (singleton) metrics manager instance (see
309/// @ref balm_defaultmetricsmanager )
310///
311/// * Simple macros for recording metrics to the default (singleton) metrics
312/// manager instance (see @ref balm_metrics )
313///
314/// * Simple types for recording metrics (see @ref balm_metric and
315/// @ref balm_integermetric )
316///
317/// * A guard helper class for recording the elapsed time of a block of code to a
318/// metric (see @ref balm_stopwatchscopedguard )
319///
320/// * The ability to enable and disable the collection and publication of
321/// categories of metrics (see @ref balm_metricsmanager and @ref balm_category )
322///
323/// * A scheduling mechanism for configuring the periodic publication of metrics
324/// (see @ref balm_publicationscheduler )
325///
326/// ## Multi-Threading {#balm-multi-threading}
327///
328/// The components provided by the 'balm' package were designed for use in
329/// multi-threaded applications. Metrics can be safely collected and published
330/// simultaneously from multiple threads. Nevertheless, not every individual
331/// component in the 'balm' package is thread-safe. See the individual component
332/// documentation for more information.
333///
334/// ## Collecting Metrics {#balm-collecting-metrics}
335///
336/// The 'balm' package defines several ways to collect metrics, as well as
337/// allowing users to define their own collection mechanisms.
338///
339/// ### Choosing Between @ref balm_metric and @ref balm_integermetric {#balm-choosing-between-ref-balm_metric-and-ref-balm_integermetric}
340///
341/// The @ref balm_metric and @ref balm_integermetric components both define macros and
342/// helper classes for recording metrics. The mechanisms in @ref balm_integermetric
343/// are slightly more efficient for collecting integral metric values, but are
344/// otherwise identical.
345///
346/// ### Choosing Between Metric Collection Macros and Metric Collection Classes {#balm-choosing-between-metric-collection-macros-and-metric-collection-classes}
347///
348/// The macros and classes defined by the @ref balm_metric , @ref balm_integermetric and
349/// @ref balm_metrics components provide the same basic functionality. Clients may
350/// find the 'balm_Metric' or 'balm_IntegerMetric' classes better suited to
351/// collecting metrics associated with a particular instance of a stateful object,
352/// while the 'BALM_METRICS_*' macros are better suited to collecting metrics
353/// associated with a particular code path (rather than an object instance). In
354/// most instances, however, choosing between the two is a matter of taste.
355///
356/// ### Creating a User Defined Collection Mechanism {#balm-creating-a-user-defined-collection-mechanism}
357///
358/// The 'balm' package allows users to define their own metric collection
359/// mechanisms by registering a callback with a 'balm_MetricsManager' object.
360/// User defined callbacks must match the
361/// 'balm_MetricsManager::MetricsCollectionCallback' function signature and
362/// collect metrics for a *single* category. Every time 'publish' is invoked for
363/// a category, the metrics manager will invoke the registered collection
364/// callbacks for that category, and publish the collected metrics. See
365/// @ref balm_metricsmanager for more information.
366///
367/// ## Publishing Metrics {#balm-publishing-metrics}
368///
369/// The @ref balm_publisher component defines a protocol for publishing metric
370/// records. Users can register publisher objects with a metrics manager.
371/// Invoking 'publish()' on a metrics manager will collect metrics for the set of
372/// categories supplied with the function call, and then publish the metrics for
373/// each supplied category to publishers registered for that category.
374///
375/// The 'balm_StreamPublisher' class implements the 'balm_Publisher' protocol to
376/// provide a default publisher for publishing metrics to a stream.
377///
378/// ## Periodically Publishing Metrics {#balm-periodically-publishing-metrics}
379///
380/// Users can schedule the periodic publication of metrics using the
381/// @ref balm_publicationscheduler component. In the example presented above, under
382/// "Getting Started", a 'balm_PublicationScheduler' object was configured to
383/// publish all categories of metrics metrics every 30 seconds.
384///
385/// At construction, a 'balm_PublicationScheduler' object is provided the
386/// addresses of a 'balm_MetricsManager' and a 'bcep_TimerEventScheduler'. Users
387/// can call 'scheduleCategory()' to schedule an individual metric category to be
388/// published repeatedly at a given interval, or call 'setDefaultSchedule()' to
389/// schedule the publication of any category not given an individual schedule. At
390/// the end of a scheduled time interval, the publication scheduler invokes the
391/// metrics manager's 'publish()' operation with the set of categories to publish.
392/// Note that, the publication scheduler will combine categories that occur at the
393/// same frequency into a single invocation of the metrics manager's 'publish'
394/// operation.
395///
396/// ## Disabling Metric Categories {#balm-disabling-metric-categories}
397///
398/// Users can disable (and re-enable) a category of metrics by calling
399/// 'balm_MetricsManager::setCategoryEnabled' method. A disabled category will
400/// not be published by the metrics manager. In addition, the @ref balm_metric ,
401/// @ref balm_integermetric , @ref balm_metrics , and @ref balm_stopwatchscopedguard
402/// components will not collect metrics for disabled categories (minimizing the
403/// performance cost of collecting metric for disabled categories). Note that
404/// when 'balm_MetricsManager::publish()' is called on a disabled category, the
405/// metrics manager *will* invoke any user defined collection callbacks registered
406/// for the disable category, but *will* *not* publish the collected metrics.
407/// Users defining their own metrics collection mechanism (using a
408/// 'balm_MetricsManager::MetricsCollectionCallback') must (manually) test whether
409/// a category is disabled if they wish to avoid collecting metrics for a disabled
410/// category.
411///
412/// @}
413/** @} */