BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balm_metric.h
Go to the documentation of this file.
1/// @file balm_metric.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balm_metric.h -*-C++-*-
8#ifndef INCLUDED_BALM_METRIC
9#define INCLUDED_BALM_METRIC
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: balm_metric.h,v 1.7 2008/04/17 21:22:34 hversche Exp $")
13
14/// @defgroup balm_metric balm_metric
15/// @brief Provide helper classes for recording metric values.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balm
19/// @{
20/// @addtogroup balm_metric
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balm_metric-purpose"> Purpose</a>
25/// * <a href="#balm_metric-classes"> Classes </a>
26/// * <a href="#balm_metric-description"> Description </a>
27/// * <a href="#balm_metric-alternative-systems-for-telemetry"> Alternative Systems for Telemetry </a>
28/// * <a href="#balm_metric-choosing-between-balm-metric-and-macros"> Choosing between balm::Metric and Macros </a>
29/// * <a href="#balm_metric-thread-safety"> Thread Safety </a>
30/// * <a href="#balm_metric-usage"> Usage </a>
31/// * <a href="#balm_metric-example-1-metric-collection-with-balm-metric"> Example 1: Metric Collection With balm::Metric </a>
32/// * <a href="#balm_metric-example-2-create-and-access-the-default-balm-metricsmanager-instance"> Example 2: Create and Access the Default balm::MetricsManager Instance </a>
33///
34/// # Purpose {#balm_metric-purpose}
35/// Provide helper classes for recording metric values.
36///
37/// # Classes {#balm_metric-classes}
38///
39/// - balm::Metric: container for recording metric values
40///
41/// @see balm_metricsmanager, balm_defaultmetricsmanager,
42/// balm_integermetric, balm_metrics
43///
44/// # Description {#balm_metric-description}
45/// This component provides a class, `balm::Metric`, to simplify
46/// the process of collecting metrics. A metric records the number of times an
47/// event occurs, as well as an associated measurement value. This component
48/// does *not* define what constitutes an event or what the associated value
49/// represents. A metric maintains a count of event occurrences and the
50/// aggregated minimum, maximum, and total of the measured metric-event values.
51///
52/// The `balm::Metric` class, defined in this component, has in-core value
53/// semantics. Each `balm::Metric` object holds a pointer to a
54/// `balm::Collector` that collects values for a particular metric. The
55/// `balm::Collector` is either supplied at construction, or else obtained from
56/// a `balm::MetricsManager` object's `balm::CollectorRepository`. If the
57/// supplied `balm::MetricsManager` is 0, the metric will use the default
58/// metrics manager instance (`balm::DefaultMetricsManager::instance()`), if
59/// initialized; otherwise, the metric is placed in the inactive state (i.e.,
60/// `isActive()` is `false`) and operations that would otherwise update the
61/// metric will have no effect.
62///
63/// ## Alternative Systems for Telemetry {#balm_metric-alternative-systems-for-telemetry}
64///
65///
66/// Bloomberg software may alternatively use the GUTS telemetry API, which is
67/// integrated into Bloomberg infrastructure.
68///
69/// ## Choosing between balm::Metric and Macros {#balm_metric-choosing-between-balm-metric-and-macros}
70///
71///
72/// The `balm::Metric` class and the macros defined in @ref balm_metrics provide
73/// the same basic functionality. Clients may find `balm::Metric` objects
74/// better suited to collecting metrics associated with a particular instance
75/// of a stateful object, while macros are better suited to collecting metrics
76/// associated with a particular code path (rather than an object instance).
77/// In most instances, however, choosing between the two is simply a matter of
78/// taste.
79///
80/// ## Thread Safety {#balm_metric-thread-safety}
81///
82///
83/// `balm::Metric` is fully *thread-safe*, meaning that all non-creator
84/// operations on a given instance can be safely invoked simultaneously from
85/// multiple threads.
86///
87/// ## Usage {#balm_metric-usage}
88///
89///
90/// This section illustrates intended use of this component.
91///
92/// ### Example 1: Metric Collection With balm::Metric {#balm_metric-example-1-metric-collection-with-balm-metric}
93///
94///
95/// We can use `balm::Metric` objects to record metric values. In this
96/// example we implement a hypothetical event manager object. We use
97/// `balm::Metric` objects to record metrics for the size of the request, the
98/// elapsed processing time, and the number of failures.
99/// @code
100/// class EventManager {
101///
102/// // DATA
103/// balm::Metric d_messageSize;
104/// balm::Metric d_elapsedTime;
105/// balm::Metric d_failedRequests;
106///
107/// public:
108///
109/// // CREATORS
110/// EventManager()
111/// : d_messageSize("MyCategory", "EventManager/size")
112/// , d_elapsedTime("MyCategory", "EventManager/elapsedTime")
113/// , d_failedRequests("MyCategory", "EventManager/failedRequests")
114/// {}
115///
116/// // MANIPULATORS
117/// int handleEvent(int eventId, const bsl::string& eventMessage)
118/// // Process the event described by the specified 'eventId' and
119/// // 'eventMessage' . Return 0 on success, and a non-zero value
120/// // if there was an error handling the event.
121/// {
122/// (void)eventId;
123///
124/// int returnCode = 0;
125///
126/// d_messageSize.update(static_cast<double>(eventMessage.size()));
127/// bsls::Stopwatch stopwatch;
128/// stopwatch.start();
129///
130/// // Process 'data' ('returnCode' may change).
131///
132/// if (0 != returnCode) {
133/// d_failedRequests.increment();
134/// }
135///
136/// d_elapsedTime.update(stopwatch.elapsedTime());
137/// return returnCode;
138/// }
139///
140/// // ...
141/// };
142/// @endcode
143///
144/// ### Example 2: Create and Access the Default balm::MetricsManager Instance {#balm_metric-example-2-create-and-access-the-default-balm-metricsmanager-instance}
145///
146///
147/// This example demonstrates how to create the default `balm::MetricManager`
148/// instance and perform a trivial configuration.
149///
150/// First we create a `balm::DefaultMetricsManagerScopedGuard`, which manages
151/// the lifetime of the default metrics manager instance. At construction, we
152/// provide the scoped guard an output stream (`stdout`) that it will publish
153/// metrics to. Note that the default metrics manager is intended to be created
154/// and destroyed by the *owner* of `main`. An instance of the manager should
155/// be created during the initialization of an application (while the task has a
156/// single thread) and destroyed just prior to termination (when there is
157/// similarly a single thread).
158/// @code
159/// int main(int argc, char *argv[])
160/// {
161/// // ...
162///
163/// balm::DefaultMetricsManagerScopedGuard managerGuard(bsl::cout);
164/// @endcode
165/// Once the default instance has been created, it can be accessed using the
166/// `instance` operation.
167/// @code
168/// balm::MetricsManager *manager =
169/// balm::DefaultMetricsManager::instance();
170/// assert(0 != manager);
171/// @endcode
172/// Note that the default metrics manager will be released when `managerGuard`
173/// exits this scoped and is destroyed. Clients that choose to explicitly call
174/// `balm::DefaultMetricsManager::create` must also explicitly call
175/// `balm::DefaultMetricsManager::release()`.
176///
177/// Now that we have created a `balm::MetricsManager` instance, we can use the
178/// instance to publish metrics collected using the event manager described in
179/// {Example 1}:
180/// @code
181/// EventManager eventManager;
182///
183/// eventManager.handleEvent(0, "ab");
184/// eventManager.handleEvent(0, "abc");
185/// eventManager.handleEvent(0, "abc");
186/// eventManager.handleEvent(0, "abdef");
187///
188/// manager->publishAll();
189///
190/// eventManager.handleEvent(0, "ab");
191/// eventManager.handleEvent(0, "abc");
192/// eventManager.handleEvent(0, "abc");
193/// eventManager.handleEvent(0, "abdef");
194///
195/// eventManager.handleEvent(0, "a");
196/// eventManager.handleEvent(0, "abc");
197/// eventManager.handleEvent(0, "abc");
198/// eventManager.handleEvent(0, "abdefg");
199///
200/// manager->publishAll();
201/// }
202/// @endcode
203/// @}
204/** @} */
205/** @} */
206
207/** @addtogroup bal
208 * @{
209 */
210/** @addtogroup balm
211 * @{
212 */
213/** @addtogroup balm_metric
214 * @{
215 */
216
217#include <balscm_version.h>
218
219#include <balm_collector.h>
222#include <balm_metricid.h>
223#include <balm_metricsmanager.h>
224#include <balm_publicationtype.h>
225
226#include <bsls_atomic.h>
227
228
229
230namespace balm {
231 // ============
232 // class Metric
233 // ============
234
235/// This class provides an in-core value semantic type for recording and
236/// aggregating the values of a metric. The value of a `Metric` object is
237/// characterized by the `Collector` object it uses to collect metric-event
238/// values. Each instance of this class establishes (at construction) an
239/// association to a `Collector` object to which the metric delegates. A
240/// `Metric` value is constant after construction (i.e., it does not support
241/// assignment or provide manipulators that modify its collector value) so
242/// that synchronization primitives are not required to protect its data
243/// members. Note that if a collector or metrics manager is not supplied at
244/// construction, and if the default metrics manager has not been
245/// instantiated, then the metric will be inactive (i.e.,
246/// `isActive() == false`) and the manipulator methods of the metric object
247/// will have no effect.
248///
249/// See @ref balm_metric
250class Metric {
251
252 // DATA
253 Collector *d_collector_p; // collected metric data (held, not owned); may
254 // be 0, but cannot be invalid
255
256 const bsls::AtomicInt
257 *d_isEnabled_p; // memo for isActive()
258
259 // NOT IMPLEMENTED
260 Metric& operator=(Metric& );
261
262 public:
263 // CLASS METHODS
264
265 /// Return a collector corresponding to the specified metric `category`
266 /// and `name`. Optionally specify a metrics `manager` used to provide
267 /// the collector. If `manager` is 0, use the default metrics manager
268 /// if initialized; if `manager` is 0 and the default metrics manager
269 /// has not been initialized, return 0. The behavior is undefined
270 /// unless `category` and `name` are null-terminated.
271 static Collector *lookupCollector(const char *category,
272 const char *name,
273 MetricsManager *manager = 0);
274
275 /// Return a collector for the specified `metricId`. Optionally specify
276 /// a metrics `manager` used to provide the collector. If `manager` is
277 /// 0, use the default metrics manager, if initialized; if `manager` is
278 /// 0 and the default metrics manager has not been initialized, return
279 /// 0. The behavior is undefined unless `metricId` is a valid metric
280 /// id supplied by the `MetricsRegistry` of the indicated metrics
281 /// manager.
283 MetricsManager *manager = 0);
284
285 // CREATORS
286
287 /// Create a metric object to collect values for the metric identified
288 /// by the specified null-terminated strings `category` and `name`.
289 /// Optionally specify a metrics `manager` used to provide a collector
290 /// for the indicated metric. If `manager` is 0, use the default
291 /// metrics manager, if initialized; if `manager` is 0 and the default
292 /// metrics manager has not been initialized, place this metric object
293 /// in the inactive state (i.e., `isActive()` is `false`) in which case
294 /// instance methods that would otherwise update the metric will have no
295 /// effect.
296 Metric(const char *category,
297 const char *name,
298 MetricsManager *manager = 0);
299
300 /// Create a metric object to collect values for the specified
301 /// `metricId`. Optionally specify a metrics `manager` used to provide
302 /// a collector for `metricId`. If `manager` is 0, use the default
303 /// metrics manager, if initialized; if `manager` is 0 and the default
304 /// metrics manager has not been initialized, place this metric object
305 /// in the inactive state (i.e., `isActive()` is `false`) in which case
306 /// instance methods that would otherwise update the metric will have
307 /// no effect. The behavior is undefined unless `metricId` is a valid
308 /// id returned by the `MetricRepository` object owned by the indicated
309 /// metrics manager.
310 explicit Metric(const MetricId& metricId,
311 MetricsManager *manager = 0);
312
313 /// Create a metric object to collect values for the metric implied by
314 /// the specified `collector` (i.e., `collector->metricId()`). The
315 /// behavior is undefined unless `collector` is a valid address of a
316 /// `Collector` object and `collector` has a valid id (i.e.,
317 /// `collector->metricId().isValid()`).
318 explicit Metric(Collector *collector);
319
320 /// Create a metric object that will record values for the same metric
321 /// (i.e., using the same `Collector` object) as the specified
322 /// `original` metric. If the `original` metric is inactive (i.e.,
323 /// `isActive()` is `false`), then this metric will be similarly
324 /// inactive.
325 Metric(const Metric& original);
326
327 /// Destroy this object.
329
330 // MANIPULATORS
331
332 /// Increase the count and total of this metric by 1; if 1.0 is less
333 /// than the current minimum recorded value of the metric, set the new
334 /// minimum value to be 1.0; if 1.0 is greater than the current maximum
335 /// recorded value, set the new maximum value to be 1.0. If, however,
336 /// this metric is not active (i.e., `isActive()` is `false`) then this
337 /// method has no effect. Note that this method is functionally
338 /// equivalent to `update(1)`.
339 void increment();
340
341 /// Increase the event count by 1 and add the specified `value` to the
342 /// total recorded value; if `value` is less than the current minimum
343 /// recorded value of the metric, set the new minimum value to be
344 /// `value`; if `value` is greater than the current maximum recorded
345 /// value, set the new maximum value to be `value`. If, however, this
346 /// metric is inactive (i.e., `isActive()` is `false`), then this method
347 /// has no effect.
348 void update(double value);
349
350 /// Increase the event count by the specified `count` and add the
351 /// specified `total` to the accumulated total; if the specified `min`
352 /// is less than the current minimum recorded value of the metric, set
353 /// the new minimum value to be `min`; if the specified `max` is
354 /// greater than the current maximum recorded value, set the new
355 /// maximum value to be `max`. If, however, this metric is inactive
356 /// (i.e., `isActive()` is `false`), then this method has no effect.
357 void accumulateCountTotalMinMax(int count,
358 double total,
359 double min,
360 double max);
361
362 /// Return the address of the modifiable collector for this metric.
364
365 // ACCESSORS
366
367 /// Return the address of the non-modifiable collector for this metric.
368 const Collector *collector() const;
369
370 /// Return a `MetricId` object identifying this metric. If this metric
371 /// was not supplied a valid collector at construction then the returned
372 /// id will be invalid (i.e., `metricId().isValid() == false`).
373 MetricId metricId() const;
374
375 /// Return `true` if this metric will actively record metrics, and
376 /// `false` otherwise. If the returned value is `false`, the
377 /// manipulator operations will have no effect. A metric will be
378 /// inactive if either (1) it was not initialized with a valid metric
379 /// identifier or (2) the associated metric category has been disabled
380 /// (see the `MetricsManager` method `setCategoryEnabled`). Note that
381 /// invoking this method is logically equivalent to the expression
382 /// `0 != collector() && metricId().category()->enabled()`.
383 bool isActive() const;
384};
385
386// ============================================================================
387// INLINE DEFINITIONS
388// ============================================================================
389
390// FREE OPERATORS
391
392/// Return `true` if the specified `lhs` and `rhs` metrics have the same
393/// value and `false` otherwise. Two metrics have the same value if they
394/// record measurements using the same collector object or if they both
395/// have a null collector (i.e., `collector()` is 0).
396inline
397bool operator==(const Metric& lhs, const Metric& rhs);
398
399/// Return `true` if the specified `lhs` and `rhs` metrics do not have the
400/// same value and `false` otherwise. Two metrics do not have the same
401/// value if they record measurements using different collector objects or
402/// if one, but not both, have a null collector (i.e., `collector()` is 0).
403inline
404bool operator!=(const Metric& lhs, const Metric& rhs);
405
406 // =====================
407 // class Metric_MacroImp
408 // =====================
409
410/// This structure provides a namespace for functions used to implement the
411/// macros defined by this component.
412///
413/// This is an implementation type of this component and *must* *not* be
414/// used by clients of the `balm` package.
416
417 // CLASS METHODS
418
419 /// Load the specified `collector` with the address of the default
420 /// collector (from the default metrics manager) for the specified
421 /// `metric` identified by the specified `category` and `name`, and
422 /// register the specified `holder` for `category`. Note that
423 /// `*collector` must be assigned *before* registering `holder` to
424 /// ensure that the macros always have a valid `collector` when
425 /// `holder->enabled()` is `true`.
426 static void getCollector(Collector **collector,
427 CategoryHolder *holder,
428 const char *category,
429 const char *metric);
430
431 /// Load the specified `collector` with the address of the default
432 /// collector (from the default metrics manager) for the specified
433 /// `metric` identified by the specified `category` and `name`, register
434 /// the specified `holder` for `category`, and set the identified
435 /// metric's preferred publication type to the specified
436 /// `preferredPublicationType`. Note that `*collector` must be
437 /// assigned before `holder` to ensure that the macros always have a
438 /// valid `collector` when `holder->enabled()` is `true`.
439 static void getCollector(Collector **collector,
440 CategoryHolder *holder,
441 const char *category,
442 const char *metric,
443 PublicationType::Value preferredPublicationType);
444};
445
446// ============================================================================
447// INLINE FUNCTION DEFINITIONS
448// ============================================================================
449
450 // ------------
451 // class Metric
452 // ------------
453
454// CLASS METHODS
455inline
456Collector *Metric::lookupCollector(const char *category,
457 const char *name,
458 MetricsManager *manager)
459{
460 manager = DefaultMetricsManager::manager(manager);
461 return manager
462 ? manager->collectorRepository().getDefaultCollector(category, name)
463 : 0;
464}
465
466inline
468 MetricsManager *manager)
469{
470 manager = DefaultMetricsManager::manager(manager);
471 return manager
473 : 0;
474}
475
476// CREATORS
477inline
478Metric::Metric(const char *category,
479 const char *name,
480 MetricsManager *manager)
481: d_collector_p(lookupCollector(category, name, manager))
482{
483 d_isEnabled_p = (d_collector_p
484 ? &d_collector_p->metricId().category()->isEnabledRaw() : 0);
485}
486
487inline
488Metric::Metric(const MetricId& metricId,
489 MetricsManager *manager)
490: d_collector_p(lookupCollector(metricId, manager))
491{
492 d_isEnabled_p = (d_collector_p
493 ? &d_collector_p->metricId().category()->isEnabledRaw() : 0);
494}
495
496inline
498: d_collector_p(collector)
499{
500 d_isEnabled_p = &d_collector_p->metricId().category()->isEnabledRaw();
501}
502
503inline
504Metric::Metric(const Metric& original)
505: d_collector_p(original.d_collector_p)
506, d_isEnabled_p(original.d_isEnabled_p)
507{
508}
509
510// MANIPULATORS
511inline
513{
514 if (isActive()) {
515 d_collector_p->update(1.0);
516 }
517}
518
519inline
520void Metric::update(double value)
521{
522 if (isActive()) {
523 d_collector_p->update(value);
524 }
525}
526
527inline
529 double total,
530 double min,
531 double max)
532{
533 if (isActive()) {
534 d_collector_p->accumulateCountTotalMinMax(count, total, min, max);
535 }
536}
537
538inline
540{
541 return d_collector_p;
542}
543
544// ACCESSORS
545inline
547{
548 return d_collector_p;
549}
550
551inline
553{
554 return d_collector_p ? d_collector_p->metricId() : MetricId();
555}
556
557inline
559{
560 return d_isEnabled_p && d_isEnabled_p->loadRelaxed();
561}
562
563} // close package namespace
564
565// FREE OPERATORS
566inline
567bool balm::operator==(const Metric& lhs, const Metric& rhs)
568{
569 return lhs.collector() == rhs.collector();
570}
571
572inline
573bool balm::operator!=(const Metric& lhs, const Metric& rhs)
574{
575 return !(lhs == rhs);
576}
577
578
579
580#endif
581
582// ----------------------------------------------------------------------------
583// Copyright 2015 Bloomberg Finance L.P.
584//
585// Licensed under the Apache License, Version 2.0 (the "License");
586// you may not use this file except in compliance with the License.
587// You may obtain a copy of the License at
588//
589// http://www.apache.org/licenses/LICENSE-2.0
590//
591// Unless required by applicable law or agreed to in writing, software
592// distributed under the License is distributed on an "AS IS" BASIS,
593// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
594// See the License for the specific language governing permissions and
595// limitations under the License.
596// ----------------------------- END-OF-FILE ----------------------------------
597
598/** @} */
599/** @} */
600/** @} */
Definition balm_category.h:257
const bsls::AtomicInt & isEnabledRaw() const
Definition balm_category.h:346
Collector * getDefaultCollector(const char *category, const char *metricName)
Definition balm_collectorrepository.h:437
Definition balm_collector.h:152
void accumulateCountTotalMinMax(int count, double total, double min, double max)
Definition balm_collector.h:281
const MetricId & metricId() const
Definition balm_collector.h:308
void update(double value)
Definition balm_collector.h:271
Definition balm_metricid.h:162
const Category * category() const
Definition balm_metricid.h:319
Definition balm_metric.h:250
void accumulateCountTotalMinMax(int count, double total, double min, double max)
Definition balm_metric.h:528
MetricId metricId() const
Definition balm_metric.h:552
static Collector * lookupCollector(const char *category, const char *name, MetricsManager *manager=0)
Definition balm_metric.h:456
void increment()
Definition balm_metric.h:512
void update(double value)
Definition balm_metric.h:520
bool isActive() const
Definition balm_metric.h:558
~Metric()
Destroy this object.
Metric(const char *category, const char *name, MetricsManager *manager=0)
Definition balm_metric.h:478
Collector * collector()
Return the address of the modifiable collector for this metric.
Definition balm_metric.h:539
Definition balm_metricsmanager.h:490
CollectorRepository & collectorRepository()
Definition balm_metricsmanager.h:1013
Definition bsls_atomic.h:743
int loadRelaxed() const
Definition bsls_atomic.h:1738
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition balm_bdlmmetricsadapter.h:141
bool operator==(const IntegerMetric &lhs, const IntegerMetric &rhs)
bool operator!=(const IntegerMetric &lhs, const IntegerMetric &rhs)
static MetricsManager * manager(MetricsManager *manager=0)
Definition balm_defaultmetricsmanager.h:302
Definition balm_metric.h:415
static void getCollector(Collector **collector, CategoryHolder *holder, const char *category, const char *metric, PublicationType::Value preferredPublicationType)
static void getCollector(Collector **collector, CategoryHolder *holder, const char *category, const char *metric)
Value
Definition balm_publicationtype.h:81