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