BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balm_metricsmanager

Detailed Description

Outline

Purpose

Provide a manager for recording and publishing metric data.

Classes

See also
balm_publisher, balm_collectorrepository, balm_metricregistry, balm_metric, balm_defaultmetricsmanager, balm_publicationscheduler

Description

This component provides a balm::MetricsManager class for managing the recording and publishing of metric data. The metrics manager retrieves balm::MetricRecords from both the collector repository it owns as well as any RecordsCollectionCallbacks registered with it. The metrics manager also provides methods to register balm::Publisher objects. The publish method collects metrics for a category (or set of categories) and then sends the collected metrics to the publishers associated with that category (or set of categories).

Note that a metric in this context is an event associated with a measured value. This component does not define what constitutes an event or what the associated value represents. A collected metric contains the count of event occurrences along with the total, minimum, and maximum aggregates of the measured values.

Alternative Systems for Telemetry

Bloomberg software may alternatively use the GUTS telemetry API, which is integrated into Bloomberg infrastructure.

Thread Safety

balm::MetricsManager is fully thread-safe, meaning that all non-creator operations on a given instance can be safely invoked simultaneously from multiple threads. To avoid synchronization problems with user functions invoked by balm::MetricsManager, special consideration must be taken when implementing these functions as specified below.

Registered Concrete balm::Publisher Implementations

Concrete implementations of the balm::Publisher protocol (pure abstract base-class) registered with a balm::MetricsManager object must not call (either directly or indirectly) the publish method on the balm::MetricsManager object with which they are registered.

Registered RecordsCollectionCallback Implementations

Implementations of balm::MetricsManager::RecordsCollectionCallback registered with a balm::MetricsManager will be invoked by a function holding mutex locks that provide synchronized access to data in that balm::MetricsManager. Therefore registered implementations of RecordsCollectionCallback must not make any re-entrant calls (either directly or indirectly) to member functions of the balm::MetricManager object with which they are registered.

Usage

This section illustrates intended use of this component.

Example 1: Initialize a balm::MetricsManager

This example demonstrates how to create and configure a balm::MetricsManager that we will use to record and publish metric values. We first create a balm::MetricsManager object and a SimpleStreamPublisher object. Note that SimpleStreamPublisher is an example implementation of the balm::Publisher protocol defined in the balm_publisher component. In practice, clients typically use a standard publisher class (e.g., balm::StreamPublisher).

int main(int argc, char *argv[]) {
{
// ...
balm::MetricsManager manager(allocator);
new (*allocator) SimpleStreamPublisher(bsl::cout),
allocator);
manager.addGeneralPublisher(publisher);
// ...
Definition balm_metricsmanager.h:490
Definition bslstl_sharedptr.h:1830
Definition bslma_allocator.h:457
static Allocator * allocator(Allocator *basicAllocator=0)
Definition bslma_default.h:897

Example 2: Recording Metric Values with balm::Collector

This second example demonstrates using balm::Collector objects (obtained from a metrics manager's collector repository) to collect metrics related to a hypothetical EventHandler class. On construction, the event handler obtains references to balm::Collector objects from the metrics manager's collector repository. On each handled event, the EventHandler, updates its collectors with the appropriate metric values.

Note that the balm_metric component provides both classes and macros to reduce the code required for collecting metric values.

class EventHandler {
// Provide an example event-handling mechanism that records metrics
// for (1) the size of the processed event messages and (2) the number
// of failures, using 'balm::Collector' objects provided by a
// 'balm::MetricsManager'.
// PRIVATE DATA
balm::Collector *d_eventMessageSizes_p; // collect the message sizes
balm::Collector *d_eventFailures_p; // collect the number of
// failures
// ...
public:
// CREATORS
Definition balm_collector.h:152

We obtain the addresses of the respective balm::Collector objects that we will use to collect metrics values from the metrics managers' collector repository. Note that, in practice, clients can use the balm::DefaultMetricManager (see balm_defaultmetricsmanager and balm_metric ) rather than explicitly pass the address of a metrics manager.

EventHandler(balm::MetricsManager *manager)
: d_eventMessageSizes_p(
manager->collectorRepository().getDefaultCollector(
"MyCategory", "messageSizes"))
, d_eventFailures_p(
manager->collectorRepository().getDefaultCollector(
"MyCategory", "eventFailures"))
{}
// MANIPULATORS

Then, when processing an "event", we update the balm::Collector objects with the appropriate metric values for the event.

int handleEvent(int eventId, const bsl::string& eventMessage)
// Process the event described by the specified 'eventId' and
// 'eventMessage' . Return 0 on success, and a non-zero value
// if there was an error handling the event.
{
int returnCode = 0;
d_eventMessageSizes_p->update(
static_cast<double>(eventMessage.size()));
// ... (Process the event)
(void)eventId;
if (0 != returnCode) {
d_eventFailures_p->update(1);
}
return returnCode;
}
// ...
};
void update(double value)
Definition balm_collector.h:271
Definition bslstl_string.h:1281
size_type size() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6592

Example 3: Recording Metric Values with a Callback

The metrics manager provides a facility to register a callback that will report metric values. A callback should be used if clients want to customize how a metric, or group of metrics, are recorded. In the following example, the EventHandlerWithCallback class maintains a metric for the average number of events per second that it reports through a balm::MetricsManager::MetricsCollectionCallback.

// eventhandlerwithcallback.h
class EventHandlerWithCallback {
// Provide an example event handling mechanism that records a
// metric for the number of events per second and reports that metric
// using a 'balm::MetricsManager::RecordsCollectionCallback'.
// PRIVATE DATA
bsls::AtomicInt d_numEvents; // number of events
bsls::TimeInterval d_periodStart; // start of the current
// period
balm::MetricId d_eventsPerSecId; // identifies the events-
// per-second metric
d_callbackHandle; // identifies the callback
balm::MetricsManager *d_metricsManager_p; // metrics manager (held,
// but not owned)
// ...
// PRIVATE MANIPULATORS
void collectMetricsCb(bsl::vector<balm::MetricRecord> *records,
bool resetFlag);
// Append to the specified 'records' the aggregated values of the
// metrics recorded by this event handler and, if 'resetFlag' is
// 'true', reset those metric values to their default state. Note
// that this method is intended to be used as a callback, and is
// consistent with the
// 'balm::MetricsManager::RecordsCollectionCallback' function
// prototype.
public:
// CREATORS
EventHandlerWithCallback(balm::MetricsManager *manager,
bslma::Allocator *basicAllocator = 0);
// Initialize this object to use the specified 'manager' to record
// and publish metrics. Optionally specify a 'basicAllocator'
// used to supply memory. If 'basicAllocator' is 0, the currently
// installed default allocator is used.
~EventHandlerWithCallback();
// Destroy this event handler.
// MANIPULATORS
int handleEvent(int eventId, const bsl::string& eventMessage);
// Process the event described by the specified 'eventId' and
// 'eventMessage'. Return 0 on success, and a non-zero value if
// there was an error processing the event.
// ...
};
Definition balm_metricid.h:162
int CallbackHandle
Identifies a registered RecordsCollectionCallback.
Definition balm_metricsmanager.h:509
Definition bslstl_vector.h:1025
Definition bsls_atomic.h:743
Definition bsls_timeinterval.h:301

In the implementation of EventHandlerWithCallback below, we ensure that the callback is registered on construction and removed before the object is destroyed.

// eventhandlerwithcallback.cpp
namespace {
const char *METRIC_CATEGORY = "MyCategory";
}

The callback creates metric records and populates them with data collected by the event handler.

// PRIVATE MANIPULATORS
void EventHandlerWithCallback::collectMetricsCb(
bool resetFlag)
{
int numEvents = resetFlag ?
(int)d_numEvents.swap(0) :
(int)d_numEvents;
bsls::TimeInterval elapsedTime = now - d_periodStart;
d_periodStart = now;
balm::MetricRecord record(d_eventsPerSecId);
record.count() = 1;
record.total() = numEvents / elapsedTime.totalSecondsAsDouble();
records->push_back(record);
}
Definition balm_metricrecord.h:217
void push_back(const VALUE_TYPE &value)
Definition bslstl_vector.h:3760
double totalSecondsAsDouble() const
Definition bsls_timeinterval.h:1444
static bsls::TimeInterval now()
Definition bdlt_currenttime.h:290

In the constructor, we initialize a metric id from the specified manager object's metric registry. We will also register the collection callback (collectMetricsCb) with the supplied manager.

// CREATORS
EventHandlerWithCallback::EventHandlerWithCallback(
bslma::Allocator *basicAllocator)
: d_numEvents(0)
, d_periodStart(bdlt::CurrentTime::now())
, d_eventsPerSecId()
, d_callbackHandle(balm::MetricsManager::e_INVALID_HANDLE)
, d_metricsManager_p(manager)
{
(void)basicAllocator;
d_eventsPerSecId = d_metricsManager_p->metricRegistry().getId(
METRIC_CATEGORY, "eventsPerSecond");
Definition balm_bdlmmetricsadapter.h:141
Definition bbldc_basicisma30360.h:112

We now register the callback function collectMetricsCb with the metrics manager. We use bdlf::BindUtil to bind the member function to a bsl::function matching the balm::MetricsManager::RecordsCollectionCallback function prototype. The private data member d_callbackHandle is used to store the balm::MetricsManager::CallbackHandle returned for the registered callback; we will use this handle later to remove the callback from the metrics manager.

d_callbackHandle =
d_metricsManager_p->registerCollectionCallback(
METRIC_CATEGORY,
bdlf::BindUtil::bindA(basicAllocator,
&EventHandlerWithCallback::collectMetricsCb,
this,
}
const PlaceHolder< 1 > _1
const PlaceHolder< 2 > _2

In the destructor we use the balm::MetricsManager::CallbackHandle, stored in d_callbackHandle, to remove the callback from the metrics manager. This prevents the metrics manager from invoking the callback method on an object that has already been destroyed.

EventHandlerWithCallback::~EventHandlerWithCallback()
{
int rc =
d_metricsManager_p->removeCollectionCallback(d_callbackHandle);
assert(0 == rc);
}
// MANIPULATORS
int EventHandlerWithCallback::handleEvent(int eventId,
const bsl::string& eventMessage)
{

We increment the atomic integer d_numEvents to keep track of the number events handled by the handleEvent method. If collecting a metric is expensive (e.g., metrics requiring a system call to collect), clients should test whether the metric is enabled before performing the collection operation.

// We don't test 'd_eventsPerSecId.category()->enabled())' before
// incrementing 'd_numEvents' because, in this instance, it will not
// improve performance.
++d_numEvents;
// ... (Process the event)
(void)eventId;
(void)eventMessage;
return 0;
}
// ...

Example 4: Publishing a Metric

The metrics manager provides a publish operation to publish metrics for a category or set of categories. In this example we will use the metrics manager's publishAll operation to publish all the metrics managed by the metrics manager. We will record metrics for "MyCategory" using instances of the EventHandler and EventHandlerWithCallback classes (defined above). This example assumes that an instance, manager, of the balm::MetricsManager class has been initialized as in example 1. Note that, in practice the publish operation is normally tied to a scheduling mechanism (e.g., see balm_publicationscheduler ).

EventHandler eventHandler(&manager);
EventHandlerWithCallback eventHandlerWithCallback(&manager);
eventHandler.handleEvent(0, "A 28 character event message");
eventHandlerWithCallback.handleEvent(1, "A different event message");
manager.publishAll();
eventHandler.handleEvent(0, "A 28 character event message");
eventHandler.handleEvent(0, "A 28 character event message");
eventHandlerWithCallback.handleEvent(1, "A different event message");
manager.publishAll();
void publishAll(bool resetFlag=true)

Executing the example should result in two samples being published to standard output. Each sample should contain 3 metrics belonging to the metric category "MyCategory". The metric "eventsPerSecond" is collected by the EventHandlerWithCallback, while "messageSizes", and "eventFailures" (both collected by EventHandler).

09FEB2009_18:52:51.093+0000 3 Records
Elapsed Time: 0.001358s
MyCategory.eventsPerSecond [count = 1, total = 2267.57, ... ]
MyCategory.messageSizes [count = 1, total = 28, min = 28, max = 28]
MyCategory.eventFailures [count = 0, total = 0, ... ]
09FEB2009_18:52:51.096+0000 3 Records
Elapsed Time: 0.002217s
MyCategory.eventsPerSecond [count = 1, total = 453.721, ... ]
MyCategory.messageSizes [count = 2, total = 56, min = 28, max = 28]
MyCategory.eventFailures [count = 0, total = 0, ... ]