// balm_metrics.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BALM_METRICS #define INCLUDED_BALM_METRICS #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a suite of operations for recording metric values. // //@CLASSES: // //@SEE_ALSO: balm_collector, balm_integercollector, balm_defaultmetricsmanager // //@DESCRIPTION: This component provides a suite of macros to simplify the // process of collecting metrics. A metric records the number of times an // event occurs, as well as an associated measurement value. A metric // maintains a count of event occurrences and the aggregated minimum, maximum, // and total of the measured metric-event values. Note that this component // does *not* define what constitutes an event nor what the associated value // represents. // ///Alternative Systems for Telemetry ///--------------------------------- // Bloomberg software may alternatively use the GUTS telemetry API, which is // integrated into Bloomberg infrastructure. // ///Thread Safety ///------------- // All the macros defined in this component are *thread-safe*, meaning that // they can be safely invoked simultaneously from multiple threads. It is // *not* safe, however, to invoke any of the macros defined in this component // while the default metrics manager is being either created or destroyed. // ///Macro Summary ///------------- // This section provides a brief description of the macros defined in this // component. In most cases, category and metric names supplied as macro // arguments are required to be *runtime* *constants*, meaning that their // values must be constant for the lifetime of the process. More complete // documentation is provided in the 'Macro Reference' section. //.. // BALM_METRICS_IF_CATEGORY_ENABLED(CATEGORY) // This macro behaves like an 'if' clause, executing the subsequent // (compound) statement if the specified 'CATEGORY' is enabled. // // BALM_METRICS_UPDATE(CATEGORY, METRIC1, VALUE1) // BALM_METRICS_UPDATE2(CATEGORY, METRIC1, VALUE1, METRIC2, VALUE2) // BALM_METRICS_UPDATE3(CATEGORY, METRIC1, VALUE1, ..., METRIC3, VALUE3) // BALM_METRICS_UPDATE4(CATEGORY, METRIC1, VALUE1, ..., METRIC4, VALUE4) // BALM_METRICS_UPDATE5(CATEGORY, METRIC1, VALUE1, ..., METRIC5, VALUE5) // BALM_METRICS_UPDATE6(CATEGORY, METRIC1, VALUE1, ..., METRIC6, VALUE6) // BALM_METRICS_INT_UPDATE(CATEGORY, METRIC1, VALUE1) // BALM_METRICS_INT_UPDATE2(CATEGORY, METRIC1, VALUE1, METRIC2, VALUE2) // BALM_METRICS_INT_UPDATE3(CATEGORY, METRIC1, VALUE1, ..., METRIC3, VALUE3) // BALM_METRICS_INT_UPDATE4(CATEGORY, METRIC1, VALUE1, ..., METRIC4, VALUE4) // BALM_METRICS_INT_UPDATE5(CATEGORY, METRIC1, VALUE1, ..., METRIC5, VALUE5) // BALM_METRICS_INT_UPDATE6(CATEGORY, METRIC1, VALUE1, ..., METRIC6, VALUE6) // Update each of up to 6 metrics by the corresponding values. // The supplied category and metric names must be *runtime* *constants*. // // BALM_METRICS_TYPED_UPDATE(CATEGORY, METRIC, VALUE, PREFERRED_TYPE) // BALM_METRICS_TYPED_INT_UPDATE(CATEGORY, METRIC, VALUE, PREFERRED_TYPE) // Update the identified metric by 'VALUE' and set its preferred // publication type. 'CATEGORY' and 'METRIC' must be *runtime* // *constants*. // // BALM_METRICS_INCREMENT(CATEGORY, METRIC) // Increment (by 1) the identified metric. 'CATEGORY' and 'METRIC' must // be *runtime* *constants*. // // BALM_METRICS_TYPED_INCREMENT(CATEGORY, METRIC, PREFERRED_TYPE) // Increment (by 1) the identified metric and set the metric's preferred // publication type. 'CATEGORY' and 'METRIC' must be *runtime* // *constants*. // // BALM_METRICS_DYNAMIC_UPDATE(CATEGORY, METRIC, VALUE) // BALM_METRICS_DYNAMIC_INT_UPDATE(CATEGORY, METRIC, VALUE) // Update the identified metric by 'VALUE'. This operation performs a // lookup on 'CATEGORY' and 'METRIC' on each invocation, so those values // need *not* be runtime constants. // // BALM_METRICS_DYNAMIC_INCREMENT(CATEGORY, METRIC) // Increment (by 1) the identified metric. This operation performs a // lookup on 'CATEGORY' and 'METRIC' on each invocation, so those values // need *not* be runtime constants. // // BALM_METRICS_TIME_BLOCK(CATEGORY, METRIC, TIME_UNITS) // BALM_METRICS_TIME_BLOCK_SECONDS(CATEGORY, METRIC) // BALM_METRICS_TIME_BLOCK_MILLISECONDS(CATEGORY, METRIC) // BALM_METRICS_TIME_BLOCK_MICROSECONDS(CATEGORY, METRIC) // BALM_METRICS_TIME_BLOCK_NANOSECONDS(CATEGORY, METRIC) // Update the identified metric by the elapsed (wall) time, in the // indicated units, from the instantiation point of the macro to the end // of the enclosing lexical scope. 'CATEGORY' and 'METRIC' must // be *runtime* *constants*. // // BALM_METRICS_DYNAMIC_TIME_BLOCK(CATEGORY, METRIC, TIME_UNITS) // BALM_METRICS_DYNAMIC_TIME_BLOCK_SECONDS(CATEGORY, METRIC) // BALM_METRICS_DYNAMIC_TIME_BLOCK_MILLISECONDS(CATEGORY, METRIC) // BALM_METRICS_DYNAMIC_TIME_BLOCK_MICROSECONDS(CATEGORY, METRIC) // BALM_METRICS_DYNAMIC_TIME_BLOCK_NANOSECONDS(CATEGORY, METRIC) // Update the identified metric by the elapsed (wall) time, in the // indicated units, from the instantiation point of the macro to the end // of the enclosing lexical scope. This operation performs a lookup on // 'CATEGORY' and 'METRIC' on each invocation, so those values need *not* // be runtime constants. //.. // ///Macro Reference ///--------------- // The macros defined in this component make use of the default instance of // 'balm::MetricsManager'. The macros have no effect unless the metrics // manager default instance has been initialized via a call to // 'balm::DefaultMetricsManager::create'. // // The macros defined below provide two basic operations identified by their // suffixes: update ('*_UPDATE') and increment ('*_INCREMENT'). The update // operation increments (by 1) the identified metric's count of events, // increases the metric's total by the supplied value, if the supplied value // is less than the metric's current minimum value then the minimum value is // set to the supplied value, and if the supplied value is greater than the // metric's current maximum value then the maximum value is set to the supplied // value. The increment operation is logically equivalent to an update of 1. // // The update, increment, and timing operations come in two variations: // standard, and dynamic (*_DYNAMIC_*). The standard variation maintains a // (function-scope static) cache containing the identity of the metric being // collected. This cache is initialized the *first* time the flow of control // passes through the instantiated macro, which in practice means that the // identifiers for the metric(s) passed as parameters to that macro must be // *runtime* *constants*. The dynamic variant looks up the supplied category // and metric(s) on each invocation of the macro, resulting in additional // runtime overhead compared to the standard variant. // // The following are the standard (non-dynamic) macros provided by this // component for updating a metric's value: //.. // BALM_METRICS_UPDATE(CATEGORY, METRIC, VALUE) // Update the indicated metric, identified by the specified 'CATEGORY' // and 'METRIC' names, with the specified 'VALUE'. 'CATEGORY' and // 'METRIC' must be null-terminated strings of a type convertible to // 'const char *', and 'VALUE' is assumed to be of a type convertible to // 'double'. This macro maintains a (function-scope static) cache // containing the identity of the metric being updated. This cache is // initialized using the 'CATEGORY' and 'METRIC' specified on the *first* // application of this macro at a particular instantiation point; // subsequent applications use that cached information, which in // practice means that 'CATEGORY' and 'METRIC' must be *runtime* // *constants*. If the default metrics manager has not been // initialized, or if the indicated 'CATEGORY' is currently disabled, // this macro has no effect. // // BALM_METRICS_INT_UPDATE(CATEGORY, METRIC, VALUE) // Update the indicated metric, identified by the specified 'CATEGORY' // and 'METRIC' names, with the specified *integer* 'VALUE'. 'CATEGORY' // and 'METRIC' must be null-terminated strings of a type convertible to // 'const char *', and 'VALUE' is assumed to be of a type convertible to // 'int'. This macro maintains a (function-scope static) cache // containing the identity of the metric being updated. This cache is // initialized using the 'CATEGORY' and 'METRIC' specified on the *first* // application of this macro at a particular instantiation point; // subsequent applications use that cached information, which in // practice, means that 'CATEGORY' and 'METRIC' must be *runtime* // *constants*. If the default metrics manager has not been initialized, // or if the indicated 'CATEGORY' is currently disabled, this macro has // no effect. // // BALM_METRICS_UPDATE2(CATEGORY, METRIC1, VALUE1, METRIC2, VALUE2) // BALM_METRICS_UPDATEn(CATEGORY, METRIC1, VALUE1, ..., METRICn, VALUEn) // Where 2 <= n <= 6 // Update each of the indicated metrics, identified by the specified // 'CATEGORY' name and the respective metric names 'METRIC1', 'METRIC2', // ..., 'METRICn' (2 <= n <= 6), with the corresponding specified // 'VALUE1', 'VALUE2', ..., 'VALUEn'. 'CATEGORY' and 'METRIC1', // 'METRIC2', ..., 'METRICn', must be null-terminated strings of a type // convertible to 'const char *', and 'VALUE1', 'VALUE2', ..., 'VALUEn' // are assumed to be of a type convertible to 'double'. These macros // maintain a (function-scope static) cache containing the identity of // the metrics being updated. This cache is initialized using the // 'CATEGORY' and metric identifiers specified on the *first* // application of these macros at a particular instantiation point; // subsequent applications use that cached information, which in // practice means that the 'CATEGORY' and metric identifiers must be // *runtime* *constants*. If the default metrics manager has not been // initialized, or if the indicated 'CATEGORY' is currently disabled, // these macros have no effect. // // BALM_METRICS_INT_UPDATE2(CATEGORY, METRIC1, VALUE1, METRIC2, VALUE2) // BALM_METRICS_INT_UPDATEn(CATEGORY, METRIC1, VALUE1, ..., METRICn, VALUEn) // Where 2 <= n <= 6 // Update each of the indicated metrics, identified by the specified // 'CATEGORY' name and the respective metric names 'METRIC1', 'METRIC2', // ..., 'METRICn' (2 <= n <= 6), with the corresponding specified // *integer* 'VALUE1', 'VALUE2', ..., 'VALUEn'. 'CATEGORY' and // 'METRIC1', 'METRIC2', ..., 'METRICn', must be null-terminated strings // of a type convertible to 'const char *', and 'VALUE1', 'VALUE2', ..., // 'VALUEn' are assumed to be of a type convertible to 'int'. These // macros maintain a (function-scope static) cache containing the // identity of the metrics being updated. This cache is initialized // using the 'CATEGORY' and metric identifiers specified on the *first* // application of these macros at a particular instantiation point; // subsequent applications use that cached information, which in // practice means that the 'CATEGORY' and metric identifiers must be // *runtime* *constants*. If the default metrics manager has not been // initialized, or if the indicated 'CATEGORY' is currently disabled, // these macros have no effect. // // BALM_METRICS_TYPED_UPDATE(CATEGORY, // METRIC, // VALUE, // PREFERRED_PUBLICATION_TYPE) // BALM_METRICS_TYPED_INT_UPDATE(CATEGORY, // METRIC, // VALUE, // PREFERRED_PUBLICATION_TYPE) // The behavior of these macros is logically equivalent to // 'BALM_METRICS_UPDATE(CATEGORY, METRIC, VALUE)' and // 'BALM_METRICS_INT_UPDATE(CATEGORY, METRIC, VALUE)', respectively, // except that, on the first invocation, these macros also set the // indicated metric's 'PREFERRED_PUBLICATION_TYPE'. The preferred // publication type of a metric indicates the preferred aggregate to // publish for that metric (e.g., 'COUNT', 'TOTAL', 'MIN', 'MAX', or // 'RATE'). The behavior is undefined unless // 'PREFERRED_PUBLICATION_TYPE' is convertible to // 'balm::PublicationType::Value'. Note that there is no uniform // definition for how publishers will interpret this value; an // 'UNSPECIFIED' value, however, generally indicates that all of the // collected aggregates (total, count, minimum, and maximum value) // should be published. // // BALM_METRICS_INCREMENT(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to: // 'BALM_METRICS_INT_UPDATE(CATEGORY, METRIC, 1)'. // // BALM_METRICS_TYPED_INCREMENT(CATEGORY, METRIC, PREFERRED_TYPE) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_TYPED_UPDATE(CATEGORY, METRIC, 1, PREFERRED_TYPE)'. //.. // The following are the dynamic macros provided by this component for // updating a metric's value; these macros do not statically cache the // identity of the metric and look up the supplied 'CATEGORY' and 'METRIC' on // each invocation: //.. // BALM_METRICS_DYNAMIC_UPDATE(CATEGORY, METRIC, VALUE) // Update the indicated metric, identified by the specified 'CATEGORY' // and 'METRIC' names, by the specified 'VALUE'. 'CATEGORY' and // 'METRIC' must be null-terminated strings of a type convertible to // 'const char *', and 'VALUE' is assumed to be of a type convertible to // 'double'. If the default metrics manager has not been initialized, // or if the indicated 'CATEGORY' is currently disabled, this macro has // no effect. Note that this operation looks up the 'CATEGORY' // and 'METRIC' on *each* application, resulting in (unnecessary) // additional runtime overhead (if the 'CATEGORY' and 'METRIC' values are // always the same for a particular point of call). // // BALM_METRICS_DYNAMIC_INT_UPDATE(CATEGORY, METRIC, VALUE) // Update the indicated metric, identified by the specified 'CATEGORY' // and 'METRIC' names, by the specified *integer* 'VALUE'. 'CATEGORY' // and 'METRIC' must be null-terminated strings of a type convertible to // 'const char *', and 'VALUE' is assumed to be of a type convertible // to 'int'. If the default metrics manager has not been initialized, // or if the indicated 'CATEGORY' is currently disabled, this macro has // no effect. Note that this operation looks up the 'CATEGORY' // and 'METRIC' on *each* application, resulting in (unnecessary) // additional runtime overhead (if the 'CATEGORY' and 'METRIC' values // are always the same for a particular point of call). // // BALM_METRICS_DYNAMIC_INCREMENT(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_DYNAMIC_INT_UPDATE(CATEGORY, METRIC, 1)'. //.. // The following macro, 'BALM_METRICS_IF_CATEGORY_ENABLED', allows clients to // (efficiently) determine if a (*runtime* *constant*) category is enabled: //.. // BALM_METRICS_IF_CATEGORY_ENABLED(CATEGORY) // This macro behaves like an 'if' clause, executing the subsequent // (compound) statement if the specified 'CATEGORY' is enabled. // 'CATEGORY' must be a null-terminated string of a type convertible to // 'const char *'. If the default metrics manager has not been // initialized, or if the indicated 'CATEGORY' is currently disabled, // the following statement is not executed (i.e., the 'if'-condition // is 'false'). This macro maintains a (function-scope static) cache // containing the identity of the category. This cache is initialized // using the 'CATEGORY' specified on the *first* application of this // macro at a particular instantiation point; subsequent applications // use that cached information, which in practice means that // 'CATEGORY' must be a *runtime* *constant*. *WARNING*: although the // 'BALM_METRICS_IF_CATEGORY_ENABLED' may look like a function call, // it actually consists of a declaration and an 'if' statement, which // means that the following is syntactically *incorrect*: // 'if (BALM_METRICS_IF_CATEGORY_ENABLED("myCategory")) { stuff() }'. // That should instead be written as: // 'BALM_METRICS_IF_CATEGORY_ENABLED("myCategory") { stuff(); }'. //.. // Finally, this component provides a set of macros to record the elapsed wall // time of a block of code: //.. // BALM_METRICS_TIME_BLOCK(CATEGORY, METRIC, TIME_UNITS) // Update the indicated metric, identified by the specified 'CATEGORY' // and 'METRIC' names, by the elapsed (wall) time, in the specified // 'TIME_UNITS', from the point of instantiation of the macro to the end // of the enclosing lexical scope. 'CATEGORY' and 'METRIC' must be // null-terminated strings of a type convertible to 'const char *', // while 'TIME_UNITS' is assumed to be of a type convertible to the // enumerated type 'balm::StopwatchScopedGuard::Units'. This macro // maintains a (function-scope static) cache containing the identity of // the metric being updated. This cache is initialized using the // 'CATEGORY' and 'METRIC' specified on the *first* application of this // macro at a particular instantiation point; subsequent applications // use that cached information, which in practice means that // 'CATEGORY' and 'METRIC' must be *runtime* *constants*. If the // default metrics manager has not been initialized, or the identified // 'CATEGORY' is disabled, this macro has no effect. Note that // 'TIME_UNITS' indicates the scale of value to report, but does *not* // affect the precision of the elapsed time measurement. // // BALM_METRICS_TIME_BLOCK_SECONDS(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_TIME_BLOCK' called with // 'balm::StopwatchScopedGuard::k_SECONDS'. // // BALM_METRICS_TIME_BLOCK_MILLISECONDS(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_TIME_BLOCK' called with // 'balm::StopwatchScopedGuard::k_MILLISECONDS'. // // BALM_METRICS_TIME_BLOCK_MICROSECONDS(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_TIME_BLOCK' called with // 'balm::StopwatchScopedGuard::k_MICROSECONDS'. // // BALM_METRICS_TIME_BLOCK_NANOSECONDS(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_TIME_BLOCK' called with // 'balm::StopwatchScopedGuard::k_NANOSECONDS'. // // BALM_METRICS_DYNAMIC_TIME_BLOCK(CATEGORY, METRIC, TIME_UNITS) // Update the indicated metric, identified by the specified 'CATEGORY' // and 'METRIC' names, by the elapsed (wall) time, in the specified // 'TIME_UNITS', from the instantiation of the macro to the end of the // enclosing lexical scope. 'CATEGORY' and 'METRIC' must be // null-terminated strings of a type convertible to 'const char *', // while 'TIME_UNITS' is assumed to be of a type convertible to the // enumerated type 'balm::StopwatchScopedGuard::Units'. If the default // metrics manager has not been initialized, or the identified // 'CATEGORY' is disabled, this macro has no effect. Note that // this operation looks up the 'CATEGORY' and 'METRIC' on *each* // application, resulting in (unnecessary) additional runtime overhead // (if the 'CATEGORY' and 'METRIC' values are always the same for a // particular point of call). Also note that 'TIME_UNITS' indicates the // scale of value to report, but does *not* affect the precision of the // elapsed time measurement. // // BALM_METRICS_DYNAMIC_TIME_BLOCK_SECONDS(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_DYNAMIC_TIME_BLOCK' called with // 'balm::StopwatchScopedGuard::k_SECONDS'. // // BALM_METRICS_DYNAMIC_TIME_BLOCK_MILLISECONDS(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_DYNAMIC_TIME_BLOCK' called with // 'balm::StopwatchScopedGuard::k_MILLISECONDS'. // // BALM_METRICS_DYNAMIC_TIME_BLOCK_MICROSECONDS(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_DYNAMIC_TIME_BLOCK' called with // 'balm::StopwatchScopedGuard::k_MICROSECONDS'. // // BALM_METRICS_DYNAMIC_TIME_BLOCK_NANOSECONDS(CATEGORY, METRIC) // The behavior of this macro is logically equivalent to // 'BALM_METRICS_DYNAMIC_TIME_BLOCK' called with // 'balm::StopwatchScopedGuard::k_NANOSECONDS'. //.. // ///Usage ///----- // The following examples demonstrate how to configure, collect, and publish // metrics. // ///Example 1: Create and Configure the Default 'balm::MetricsManager' Instance ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This example demonstrates how to create the default 'balm::MetricsManager' // instance and perform a trivial configuration. // // First we create a 'balm::DefaultMetricsManagerScopedGuard', which manages // the lifetime of the default metrics manager instance. At construction, we // provide this guard with an output stream ('stdout') to which the default // metrics manager will publish metrics. Note that the default metrics // manager is intended to be created and destroyed by the *owner* of 'main': // An instance of the manager should be created during the initialization of // an application (while the task has a single thread) and destroyed just // prior to termination (when there is similarly a single thread). //.. // int main(int argc, char *argv[]) // { // // ... // // balm::DefaultMetricsManagerScopedGuard managerGuard(bsl::cout); //.. // Once the default manager object has been created, it can be accessed using // the 'instance' operation. //.. // balm::MetricsManager *manager = // balm::DefaultMetricsManager::instance(); // assert(0 != manager); //.. // Note that the default metrics manager will be released when the // 'managerGuard' exits this scoped and is destroyed. Clients that choose to // explicitly call 'balm::DefaultMetricsManager::create()' must also explicitly // call 'balm::DefaultMetricsManager::release()'. // ///Example 2: Updating a Metric /// - - - - - - - - - - - - - - // Once a metrics manager is initialized, we can use the various macros to // record metric values. In this second example, we collect metrics from a // hypothetical event-processing function. We use 'BALM_METRICS_UPDATE' to // record the size of the data being processed to a metric named "msgSize", // and the elapsed time (in milliseconds) to process the event to a metric // named "elapsedTime". Finally, we use 'BALM_METRICS_INCREMENT' to record a // count of failures to a metric named "failureCount". Note that we do not use // the '*_DYNAMIC_*' variants of the 'BALM_METRICS_UPDATE' or // 'BALM_METRICS_INCREMENT' macros because the category and metric names are // constant across all applications of the macro at a particular instantiation // point (the 'DYNAMIC' variants look up the category and metric name on each // application, which would incur unnecessary runtime overhead). //.. // int processEvent(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 otherwise. // { // (void)eventId; // // int returnCode = 0; // // BALM_METRICS_UPDATE("processEvent", // "msgSize", // static_cast<double>(eventMessage.size())); // BALM_METRICS_TIME_BLOCK_MILLISECONDS("processingEvent", "elapsedTime"); // // // Process 'data'. // // if (0 != returnCode) { // BALM_METRICS_INCREMENT("processEvent", "failureCount"); // } // // return returnCode; // } //.. // ///Example 3: Using 'BALM_METRICS_IF_CATEGORY_ENABLED' ///- - - - - - - - - - - - - - - - - - - - - - - - - - // In this next example, we use 'BALM_METRICS_IF_CATEGORY_ENABLED' to // conditionally disable a (relatively) expensive operation involved in // computing a metric value. The 'processEvent2' function, defined below, uses // a 'bsls::Stopwatch' to record the elapsed system, user, and wall times, // associated with processing the event. The system calls used (via // 'bsls::Stopwatch') to record the elapsed time may be relatively expensive, // so we use 'BALM_METRICS_IF_CATEGORY_ENABLED' to ensure we perform those // operations only if metrics collection is enabled. Finally, we use // 'BALM_METRICS_UPDATE3' to update the three metrics, which is (slightly) more // efficient than updating each metric individually using 'BALM_METRIC_UPDATE'. //.. // int processEvent2(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 otherwise. // { // (void)eventId; // (void)eventMessage; // // int returnCode = 0; // // bsls::Stopwatch stopwatch; // BALM_METRICS_IF_CATEGORY_ENABLED("processEvent2") { // stopwatch.start(true); // } // // // Process 'data'. // // BALM_METRICS_IF_CATEGORY_ENABLED("processEvent2") { // double systemTime, userTime, wallTime; // stopwatch.accumulatedTimes(&systemTime, &userTime, &wallTime); // BALM_METRICS_UPDATE3("processEvent2", // "systemTime", systemTime, // "userTime", userTime, // "wallTime", wallTime); // } // // return returnCode; // } //.. #include <balscm_version.h> #include <balm_category.h> #include <balm_collector.h> #include <balm_collectorrepository.h> #include <balm_defaultmetricsmanager.h> #include <balm_integercollector.h> #include <balm_metricid.h> #include <balm_metricregistry.h> #include <balm_metricsmanager.h> #include <balm_publicationtype.h> #include <balm_stopwatchscopedguard.h> #include <bsls_performancehint.h> #include <bsls_platform.h> // ================================ // BALM_METRICS_IF_CATEGORY_ENABLED // ================================ #define BALM_METRICS_IF_CATEGORY_ENABLED(CATEGORY) \ BALM_METRICS_IF_CATEGORY_ENABLED_IMP( \ CATEGORY, BALM_METRICS_UNIQUE_NAME(categoryHolder)) // =================== // BALM_METRICS_UPDATE // =================== // Note that the static collector address must be assigned *before* // initializing category holder to ensure initialization is thread safe. #define BALM_METRICS_UPDATE(CATEGORY, METRIC1, VALUE1) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::Collector *collector1 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getCollector(CATEGORY, METRIC1); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ } \ } while (0) #define BALM_METRICS_UPDATE2(CATEGORY, METRIC1, VALUE1, METRIC2, VALUE2) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::Collector *collector1 = 0; \ static balm::Collector *collector2 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getCollector(CATEGORY, METRIC1); \ collector2 = Helper::getCollector(CATEGORY, METRIC2); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ } \ } while (0) #define BALM_METRICS_UPDATE3(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2, \ METRIC3, \ VALUE3) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::Collector *collector1 = 0; \ static balm::Collector *collector2 = 0; \ static balm::Collector *collector3 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC3, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getCollector(CATEGORY, METRIC1); \ collector2 = Helper::getCollector(CATEGORY, METRIC2); \ collector3 = Helper::getCollector(CATEGORY, METRIC3); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ collector3->update(VALUE3); \ } \ } while (0) #define BALM_METRICS_UPDATE4(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2, \ METRIC3, \ VALUE3, \ METRIC4, \ VALUE4) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::Collector *collector1 = 0; \ static balm::Collector *collector2 = 0; \ static balm::Collector *collector3 = 0; \ static balm::Collector *collector4 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC3, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC4, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getCollector(CATEGORY, METRIC1); \ collector2 = Helper::getCollector(CATEGORY, METRIC2); \ collector3 = Helper::getCollector(CATEGORY, METRIC3); \ collector4 = Helper::getCollector(CATEGORY, METRIC4); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ collector3->update(VALUE3); \ collector4->update(VALUE4); \ } \ } while (0) #define BALM_METRICS_UPDATE5(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2, \ METRIC3, \ VALUE3, \ METRIC4, \ VALUE4, \ METRIC5, \ VALUE5) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::Collector *collector1 = 0; \ static balm::Collector *collector2 = 0; \ static balm::Collector *collector3 = 0; \ static balm::Collector *collector4 = 0; \ static balm::Collector *collector5 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC3, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC4, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC5, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getCollector(CATEGORY, METRIC1); \ collector2 = Helper::getCollector(CATEGORY, METRIC2); \ collector3 = Helper::getCollector(CATEGORY, METRIC3); \ collector4 = Helper::getCollector(CATEGORY, METRIC4); \ collector5 = Helper::getCollector(CATEGORY, METRIC5); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ collector3->update(VALUE3); \ collector4->update(VALUE4); \ collector5->update(VALUE5); \ } \ } while (0) #define BALM_METRICS_UPDATE6(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2, \ METRIC3, \ VALUE3, \ METRIC4, \ VALUE4, \ METRIC5, \ VALUE5, \ METRIC6, \ VALUE6) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::Collector *collector1 = 0; \ static balm::Collector *collector2 = 0; \ static balm::Collector *collector3 = 0; \ static balm::Collector *collector4 = 0; \ static balm::Collector *collector5 = 0; \ static balm::Collector *collector6 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY, Helper::e_TYPE_CATEGORY, \ __FILE__, __LINE__); \ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC3, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC4, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC5, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC6, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getCollector(CATEGORY, METRIC1); \ collector2 = Helper::getCollector(CATEGORY, METRIC2); \ collector3 = Helper::getCollector(CATEGORY, METRIC3); \ collector4 = Helper::getCollector(CATEGORY, METRIC4); \ collector5 = Helper::getCollector(CATEGORY, METRIC5); \ collector6 = Helper::getCollector(CATEGORY, METRIC6); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ collector3->update(VALUE3); \ collector4->update(VALUE4); \ collector5->update(VALUE5); \ collector6->update(VALUE6); \ } \ } while (0) #define BALM_METRICS_TYPED_UPDATE(CATEGORY, METRIC, VALUE, PREFERRED_TYPE) \ do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::Collector *collector1 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC, Helper::e_TYPE_METRIC, __FILE__, __LINE__); \ collector1 = Helper::getCollector(CATEGORY, METRIC); \ Helper::setPublicationType(collector1->metricId(), PREFERRED_TYPE); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE); \ } \ } while (0) #define BALM_METRICS_DYNAMIC_UPDATE(CATEGORY, METRIC, VALUE) do { \ using namespace BloombergLP; \ if (balm::DefaultMetricsManager::instance()) { \ balm::CollectorRepository& repository = \ balm::DefaultMetricsManager::instance()->collectorRepository(); \ balm::Collector *collector = repository.getDefaultCollector( \ (CATEGORY), (METRIC));\ if (collector->metricId().category()->enabled()) { \ collector->update((VALUE)); \ } \ } \ } while(0) // ======================= // BALM_METRICS_INT_UPDATE // ======================= #define BALM_METRICS_INT_UPDATE(CATEGORY, METRIC1, VALUE1) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::IntegerCollector *collector1 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getIntegerCollector(CATEGORY, METRIC1); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ } \ } while (0) #define BALM_METRICS_INT_UPDATE2(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::IntegerCollector *collector1 = 0; \ static balm::IntegerCollector *collector2 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getIntegerCollector(CATEGORY, METRIC1); \ collector2 = Helper::getIntegerCollector(CATEGORY, METRIC2); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ } \ } while (0) #define BALM_METRICS_INT_UPDATE3(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2, \ METRIC3, \ VALUE3) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::IntegerCollector *collector1 = 0; \ static balm::IntegerCollector *collector2 = 0; \ static balm::IntegerCollector *collector3 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC3, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getIntegerCollector(CATEGORY, METRIC1); \ collector2 = Helper::getIntegerCollector(CATEGORY, METRIC2); \ collector3 = Helper::getIntegerCollector(CATEGORY, METRIC3); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ collector3->update(VALUE3); \ } \ } while (0) #define BALM_METRICS_INT_UPDATE4(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2, \ METRIC3, \ VALUE3, \ METRIC4, \ VALUE4) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::IntegerCollector *collector1 = 0; \ static balm::IntegerCollector *collector2 = 0; \ static balm::IntegerCollector *collector3 = 0; \ static balm::IntegerCollector *collector4 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC3, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC4, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getIntegerCollector(CATEGORY, METRIC1); \ collector2 = Helper::getIntegerCollector(CATEGORY, METRIC2); \ collector3 = Helper::getIntegerCollector(CATEGORY, METRIC3); \ collector4 = Helper::getIntegerCollector(CATEGORY, METRIC4); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ collector3->update(VALUE3); \ collector4->update(VALUE4); \ } \ } while (0) #define BALM_METRICS_INT_UPDATE5(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2, \ METRIC3, \ VALUE3, \ METRIC4, \ VALUE4, \ METRIC5, \ VALUE5) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::IntegerCollector *collector1 = 0; \ static balm::IntegerCollector *collector2 = 0; \ static balm::IntegerCollector *collector3 = 0; \ static balm::IntegerCollector *collector4 = 0; \ static balm::IntegerCollector *collector5 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC3, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC4, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC5, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getIntegerCollector(CATEGORY, METRIC1); \ collector2 = Helper::getIntegerCollector(CATEGORY, METRIC2); \ collector3 = Helper::getIntegerCollector(CATEGORY, METRIC3); \ collector4 = Helper::getIntegerCollector(CATEGORY, METRIC4); \ collector5 = Helper::getIntegerCollector(CATEGORY, METRIC5); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ collector3->update(VALUE3); \ collector4->update(VALUE4); \ collector5->update(VALUE5); \ } \ } while (0) #define BALM_METRICS_INT_UPDATE6(CATEGORY, \ METRIC1, \ VALUE1, \ METRIC2, \ VALUE2, \ METRIC3, \ VALUE3, \ METRIC4, \ VALUE4, \ METRIC5, \ VALUE5, \ METRIC6, \ VALUE6) do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::IntegerCollector *collector1 = 0; \ static balm::IntegerCollector *collector2 = 0; \ static balm::IntegerCollector *collector3 = 0; \ static balm::IntegerCollector *collector4 = 0; \ static balm::IntegerCollector *collector5 = 0; \ static balm::IntegerCollector *collector6 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC1, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC2, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC3, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC4, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC5, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ Helper::logEmptyName(METRIC6, Helper::e_TYPE_METRIC, __FILE__, __LINE__);\ collector1 = Helper::getIntegerCollector(CATEGORY, METRIC1); \ collector2 = Helper::getIntegerCollector(CATEGORY, METRIC2); \ collector3 = Helper::getIntegerCollector(CATEGORY, METRIC3); \ collector4 = Helper::getIntegerCollector(CATEGORY, METRIC4); \ collector5 = Helper::getIntegerCollector(CATEGORY, METRIC5); \ collector6 = Helper::getIntegerCollector(CATEGORY, METRIC6); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE1); \ collector2->update(VALUE2); \ collector3->update(VALUE3); \ collector4->update(VALUE4); \ collector5->update(VALUE5); \ collector6->update(VALUE6); \ } \ } while (0) #define BALM_METRICS_TYPED_INT_UPDATE(CATEGORY, \ METRIC, \ VALUE, \ PREFERRED_TYPE) \ do { \ using namespace BloombergLP; \ typedef balm::Metrics_Helper Helper; \ static balm::CategoryHolder holder = { false, 0, 0 }; \ static balm::IntegerCollector *collector1 = 0; \ if (0 == holder.category() && balm::DefaultMetricsManager::instance()) { \ Helper::logEmptyName(CATEGORY,Helper::e_TYPE_CATEGORY,__FILE__,__LINE__);\ Helper::logEmptyName(METRIC, Helper::e_TYPE_METRIC, __FILE__, __LINE__); \ collector1 = Helper::getIntegerCollector(CATEGORY, METRIC); \ Helper::setPublicationType(collector1->metricId(), PREFERRED_TYPE); \ Helper::initializeCategoryHolder(&holder, CATEGORY); \ } \ if (holder.enabled()) { \ collector1->update(VALUE); \ } \ } while (0) #define BALM_METRICS_DYNAMIC_INT_UPDATE(CATEGORY, METRIC, VALUE) do { \ using namespace BloombergLP; \ if (balm::DefaultMetricsManager::instance()) { \ balm::CollectorRepository& repository = \ balm::DefaultMetricsManager::instance()->collectorRepository(); \ balm::IntegerCollector *collector = \ repository.getDefaultIntegerCollector((CATEGORY), (METRIC)); \ if (collector->metricId().category()->enabled()) { \ collector->update((VALUE)); \ } \ } \ } while (0) #define BALM_METRICS_INCREMENT(CATEGORY, METRIC) \ BALM_METRICS_INT_UPDATE(CATEGORY, METRIC, 1) #define BALM_METRICS_TYPED_INCREMENT(CATEGORY, METRIC, PREFERRED_TYPE) \ BALM_METRICS_TYPED_INT_UPDATE(CATEGORY, METRIC, 1, PREFERRED_TYPE) #define BALM_METRICS_DYNAMIC_INCREMENT(CATEGORY, METRIC) \ BALM_METRICS_DYNAMIC_INT_UPDATE(CATEGORY, METRIC, 1) // ======================= // BALM_METRICS_TIME_BLOCK // ======================= #define BALM_METRICS_TIME_BLOCK(CATEGORY, METRIC, TIME_UNITS) \ BALM_METRICS_TIME_BLOCK_IMP((CATEGORY), \ (METRIC), \ TIME_UNITS, \ BALM_METRICS_UNIQUE_NAME(_bAlM_CoLlEcToR)) #define BALM_METRICS_DYNAMIC_TIME_BLOCK(CATEGORY, METRIC, TIME_UNITS) \ BALM_METRICS_DYNAMIC_TIME_BLOCK_IMP( \ (CATEGORY), \ (METRIC), \ TIME_UNITS, \ BALM_METRICS_UNIQUE_NAME(_bAlM_CoLlEcToR)) #define BALM_METRICS_TIME_BLOCK_SECONDS(CATEGORY, METRIC) \ BALM_METRICS_TIME_BLOCK((CATEGORY), \ (METRIC), \ BloombergLP::balm::StopwatchScopedGuard::k_SECONDS); #define BALM_METRICS_TIME_BLOCK_MILLISECONDS(CATEGORY, METRIC) \ BALM_METRICS_TIME_BLOCK( \ (CATEGORY), \ (METRIC), \ BloombergLP::balm::StopwatchScopedGuard::k_MILLISECONDS); #define BALM_METRICS_TIME_BLOCK_MICROSECONDS(CATEGORY, METRIC) \ BALM_METRICS_TIME_BLOCK( \ (CATEGORY), \ (METRIC), \ BloombergLP::balm::StopwatchScopedGuard::k_MICROSECONDS); #define BALM_METRICS_TIME_BLOCK_NANOSECONDS(CATEGORY, METRIC) \ BALM_METRICS_TIME_BLOCK( \ (CATEGORY), \ (METRIC), \ BloombergLP::balm::StopwatchScopedGuard::k_NANOSECONDS); #define BALM_METRICS_DYNAMIC_TIME_BLOCK_SECONDS(CATEGORY, METRIC) \ BALM_METRICS_DYNAMIC_TIME_BLOCK( \ (CATEGORY), \ (METRIC), \ BloombergLP::balm::StopwatchScopedGuard::k_SECONDS); #define BALM_METRICS_DYNAMIC_TIME_BLOCK_MILLISECONDS(CATEGORY, METRIC) \ BALM_METRICS_DYNAMIC_TIME_BLOCK( \ (CATEGORY), \ (METRIC), \ BloombergLP::balm::StopwatchScopedGuard::k_MILLISECONDS); #define BALM_METRICS_DYNAMIC_TIME_BLOCK_MICROSECONDS(CATEGORY, METRIC) \ BALM_METRICS_DYNAMIC_TIME_BLOCK( \ (CATEGORY), \ (METRIC), \ BloombergLP::balm::StopwatchScopedGuard::k_MICROSECONDS); #define BALM_METRICS_DYNAMIC_TIME_BLOCK_NANOSECONDS(CATEGORY, METRIC) \ BALM_METRICS_DYNAMIC_TIME_BLOCK( \ (CATEGORY), \ (METRIC), \ BloombergLP::balm::StopwatchScopedGuard::k_NANOSECONDS); // ===================== // Macro Implementations // ===================== #define BALM_METRICS_IF_CATEGORY_ENABLED_IMP(CATEGORY, HOLDER_NAME) \ static BloombergLP::balm::CategoryHolder HOLDER_NAME = { false, 0, 0 }; \ if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!HOLDER_NAME.category()) \ && BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( \ BloombergLP::balm::DefaultMetricsManager::instance() != 0)) {\ BloombergLP::balm::Metrics_Helper::initializeCategoryHolder( \ &HOLDER_NAME, CATEGORY); \ } \ if (HOLDER_NAME.enabled()) // Declare a static pointer to a 'balm::Collector' with the specified // 'VARIABLE_NAME' and an initial value of 0. If the default metrics manager // is available and the declared pointer variable (named 'VARIABLE_NAME') is 0, // assign to 'VARIABLE_NAME' the address of a collector for the specified // 'CATEGORY' and 'METRIC'. Finally, declare a 'balm::StopwatchScopedGuard' // object with a unique variable name and supply its constructor the collector // address held in 'VARIABLE_NAME' and the specified 'TIME_UNITS'. #define BALM_METRICS_TIME_BLOCK_IMP(CATEGORY, \ METRIC, \ TIME_UNITS, \ VARIABLE_NAME) \ static BloombergLP::balm::Collector *VARIABLE_NAME = 0; \ if (BloombergLP::balm::DefaultMetricsManager::instance()) { \ using namespace BloombergLP; \ if (0 == VARIABLE_NAME) { \ balm::CollectorRepository& repository = \ balm::DefaultMetricsManager::instance()->collectorRepository(); \ VARIABLE_NAME = repository.getDefaultCollector((CATEGORY), \ (METRIC)); \ } \ } \ else { \ VARIABLE_NAME = 0; \ } \ BloombergLP::balm::StopwatchScopedGuard \ BALM_METRICS_UNIQUE_NAME(__bAlM_gUaRd)(VARIABLE_NAME, TIME_UNITS); // Declare a pointer to a 'balm::Collector' with the specified 'VARIABLE_NAME'. // If the default metrics manager is available, assign to the declared pointer // variable (named 'VARIABLE_NAME') the address of a collector for the // specified 'CATEGORY' and 'METRIC'. Finally, declare a // 'balm::StopwatchScopedGuard' object with a unique variable name and supply // its constructor the collector address held in 'VARIABLE_NAME' and the // specified 'TIME_UNITS'. #define BALM_METRICS_DYNAMIC_TIME_BLOCK_IMP(CATEGORY, \ METRIC, \ TIME_UNITS, \ VARIABLE_NAME) \ BloombergLP::balm::Collector *VARIABLE_NAME = 0; \ if (BloombergLP::balm::DefaultMetricsManager::instance()) { \ using namespace BloombergLP; \ balm::CollectorRepository& repository = \ balm::DefaultMetricsManager::instance()->collectorRepository(); \ VARIABLE_NAME = repository.getDefaultCollector((CATEGORY), \ (METRIC)); \ } \ BloombergLP::balm::StopwatchScopedGuard \ BALM_METRICS_UNIQUE_NAME(__bAlM_gUaRd)(VARIABLE_NAME, TIME_UNITS); // ------------------------ // Unique line number macro // ------------------------ #if defined(BSLS_PLATFORM_CMP_MSVC) // MSVC: __LINE__ macro breaks when /ZI is used (see Q199057 or KB199057) // Fortunately the __COUNTER__ extension provided by MSVC is even better. # define BALM_METRICS_UNIQNUM __COUNTER__ #else # define BALM_METRICS_UNIQNUM __LINE__ #endif // ---------------------------------- // Token concatenation support macros // ---------------------------------- // Second layer needed to ensure that arguments are expanded before // concatenation. #define BALM_METRICS_CAT(X, Y) BALM_METRICS_CAT_IMP(X, Y) #define BALM_METRICS_CAT_IMP(X, Y) X##Y // ---------------------------------- // Unique variable name support macro // ---------------------------------- // Create a unique variable name by concatenating the specified 'X' string // with a unique integer value. #define BALM_METRICS_UNIQUE_NAME(X) \ BALM_METRICS_CAT(X, BALM_METRICS_UNIQNUM) namespace BloombergLP { namespace balm { // ===================== // struct Metrics_Helper // ===================== struct Metrics_Helper { // This 'struct' provides a namespace for a suite of functions used in the // implementation of the macros defined in this component. // // This type is an implementation detail and *must* *not* be used // (directly) by clients outside of this component. // TYPES enum NameType { // Enumeration indicating the type of identifier supplied to // 'logEmptyName'. e_TYPE_CATEGORY = 0, e_TYPE_METRIC = 1 #ifndef BDE_OMIT_INTERNAL_DEPRECATED , TYPE_CATEGORY = e_TYPE_CATEGORY , TYPE_METRIC = e_TYPE_METRIC #endif }; // CLASS METHODS static void initializeCategoryHolder(CategoryHolder *holder, const char *category); // Load into the specified 'holder' the address and enabled status of // the specified 'category', and add 'holder' to the list of category // holders for 'category'. The behavior is undefined unless the balm // metrics manager singleton is valid. static Collector *getCollector(const char *category, const char *metric); // Return the address of the default metrics collector for the metric // identified by the specified 'category' and 'metric' names. The // behavior is undefined unless the 'balm' metrics manager singleton is // valid. static IntegerCollector *getIntegerCollector(const char *category, const char *metric); // Return the address of the default integer metrics collector for the // metric identified by the specified 'category' and 'metric' names. // The behavior is undefined unless the 'balm' metrics manager // singleton is valid. static void setPublicationType(const MetricId& id, PublicationType::Value type); // Set the publication type for the metric identified by the specified // 'id' to the specified 'type'. The behavior is undefined unless the // 'balm' metrics manager singleton is valid, and 'id' is a valid // identifier supplied by the singleton metrics manager. static void logEmptyName(const char *name, NameType type, const char *file, int line); // If the specified 'name' is empty or contains only whitespace, then // log a warning message indicating whether 'name' is a category or a // metric, depending on the specified 'type', and the location at which // this function is called, indicated by the specified 'file' and // 'line'; otherwise, do nothing. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // --------------------- // struct Metrics_Helper // --------------------- // CLASS METHODS inline void Metrics_Helper::initializeCategoryHolder(CategoryHolder *holder, const char *category) { MetricsManager *manager = DefaultMetricsManager::instance(); MetricRegistry& registry = manager->metricRegistry(); registry.registerCategoryHolder(registry.getCategory(category), holder); } inline Collector *Metrics_Helper::getCollector(const char *category, const char *metric) { MetricsManager *manager = DefaultMetricsManager::instance(); return manager->collectorRepository().getDefaultCollector(category, metric); } inline IntegerCollector *Metrics_Helper::getIntegerCollector(const char *category, const char *metric) { MetricsManager *manager = DefaultMetricsManager::instance(); return manager->collectorRepository().getDefaultIntegerCollector(category, metric); } inline void Metrics_Helper::setPublicationType(const MetricId& id, PublicationType::Value type) { MetricsManager *manager = DefaultMetricsManager::instance(); return manager->metricRegistry().setPreferredPublicationType(id, type); } } // close package namespace } // close enterprise namespace #if !defined(BSL_DOUBLE_UNDERSCORE_XLAT) || 1 == BSL_DOUBLE_UNDERSCORE_XLAT #define BALM_METRICS__UNIQUE_NAME(X) BALM_METRICS_UNIQUE_NAME(X) #endif #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------