balm.txt

@PURPOSE: Provide thread-safe collection and publishing of metrics.

@MNEMONIC: Basic Application Library Metrics (balm)

@DESCRIPTION: The 'balm' package provides facilities for recording and
 publishing metric data.

 Bloomberg internal software should also consider the GUTS telemetry API, which
 is integrated into Bloomberg infrastructure.

 A "metric", in the context of this package, is a measured event.  This package
 does *not* define what constitutes an event or what the associated measurement
 represents.  For example, a metric could record the elapsed time of a function
 call (in which case the event is the function call, and the measured value is
 the elapsed time), or a metric could record the number of requests received by
 a service (in which case the event is the reception of a request, and the
 measured value is 1).

 This package provides components for collecting and aggregating measurement
 values (see 'balm_metric' and 'balm_metrics').  Those aggregated metric
 measurements are described by a metric record (see 'balm_metricrecord'), which
 contains the identifier for the recorded metric, the number of times the event
 occurred, as well as the minimum, maximum, and total of the measured values.
 This package provides a protocol for publishing metric records (see
 'balm_publisher') and an implementation of that protocol for publishing
 records to a stream (see 'balm_streampublisher).  Finally this package
 provides a 'balm_metricsmanager' component to coordinate the collection and
 publication of metrics.

/Hierarchical Synopsis
/---------------------
 The 'balm' package currently has 21 components having 13 levels of physical
 dependency.  The list below shows the hierarchical ordering of the components.
 The order of components within each level is not architecturally significant,
 just alphabetical.
..
  13. balm_configurationutil

  12. balm_metrics

  11. balm_stopwatchscopedguard

  10. balm_integermetric
      balm_metric

   9. balm_defaultmetricsmanager
      balm_publicationscheduler

   8. balm_metricsmanager
      balm_streampublisher

   7. balm_collectorrepository
      balm_publisher

   6. balm_collector
      balm_integercollector
      balm_metricsample

   5. balm_metricrecord
      balm_metricregistry

   4. balm_metricid

   3. balm_metricdescription

   2. balm_metricformat

   1. balm_category
      balm_publicationtype
..

/Component Synopsis
/------------------
: 'balm_category':
:      Provide a representation of a metric category.
:
: 'balm_collector':
:      Provide a container for collecting and aggregating metric values.
:
: 'balm_collectorrepository':
:      Provide a repository for collectors.
:
: 'balm_configurationutil':
:      Provide a namespace for metrics configuration utilities.
:
: 'balm_defaultmetricsmanager':
:      Provide for a default instance of the metrics manager.
:
: 'balm_integercollector':
:      Provide a container for collecting integral metric values.
:
: 'balm_integermetric':
:      Provide helper classes for recording int metric values.
:
: 'balm_metric':
:      Provide helper classes for recording metric values.
:
: 'balm_metricdescription':
:      Provide a description for a metric.
:
: 'balm_metricformat':
:      Provide a formatting specification for a metric.
:
: 'balm_metricid':
:      Provide an identifier for a metric.
:
: 'balm_metricrecord':
:      Provide an aggregated record of the value of a metric.
:
: 'balm_metricregistry':
:      Provide a registry for metrics.
:
: 'balm_metrics':
:      Provide a suite of operations for recording metric values.
:
: 'balm_metricsample':
:      Provide a container for a sample of collected metric records.
:
: 'balm_metricsmanager':
:      Provide a manager for recording and publishing metric data.
:
: 'balm_publicationscheduler':
:      Provide a scheduler for publishing metrics.
:
: 'balm_publicationtype':
:      Provide an enumeration of aggregate types used to publish metrics.
:
: 'balm_publisher':
:      Provide a protocol to publish recorded metric values.
:
: 'balm_stopwatchscopedguard':
:      Provide a scoped guard for recording elapsed time.
:
: 'balm_streampublisher':
:      Provide a 'balm::Publisher' implementation that writes to a stream.

/Getting Started
/---------------
 The following section presents a simple example of collecting metrics.  We
 create a trivial application that reads lines of text from standard input and
 counts the number of letters, words, and unique words in each line.  The
 function 'processLine()' processes each line of text and records metrics for
 the number of times 'processLine()' has been called, the elapsed time for the
 calls to 'processLine()', the total character count, and the total word count.

 Before we can collect metrics we must first create a 'balm_MetricsManager'
 object to manage their collection (and publication).  We use the
 'balm_DefaultMetricsManager', which is a singleton instance of the
 'balm_MetricsManager' class.  The default metrics manager is used by the
 collection macros that we will use to collect metrics (see 'balm_metrics').
 Note that the default metrics manager is intended to be created and destroyed
 by the *owner* of 'main'.  A default metrics manager instance 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, const char *argv[])
  {
..
 We create a 'balm_DefaultMetricsManagerScopedGuard', which manages the
 lifetime of the default metrics manager (singleton) instance.  At
 construction, we provide the scoped guard an output stream ('stdout') to which
 the 'balm_publisher' (created by the default metrics manager) will publish
 metrics.
..
      balm_DefaultMetricsManagerScopedGuard managerGuard(bdl::cout);
..
 We create a 'balm_PublicationScheduler' to periodically publish the metrics we
 have collected.  A 'balm_PublicationScheduler' invokes 'publish()' on the
 supplied 'balm_MetricsManager' object according to the provided schedule.
..
      bcep_TimerEventScheduler eventScheduler;
      balm_PublicationScheduler publicationScheduler(
                                     balm_DefaultMetricsManager::instance(),
                                     &eventScheduler);
..
 To begin periodically publishing metrics we 'start' the event scheduler
 supplied to the 'balm_PublicationScheduler', and then set a simple schedule to
 publish all collected metrics every 30 seconds.
..
      eventScheduler.start();
      publicationScheduler.setDefaultSchedule(bsls::TimeInterval(30, 0));
..
 Finally we have our main "application" loop, which reads lines of text from
 the standard input (until "exit" is provided as input) and calls
 'processLine()' for each line of input.
..
      while (true) {
          enum { BUFFER_SIZE = 1024 };
          char buffer[BUFFER_SIZE];
          if (!bdl::cin.getline(buffer, BUFFER_SIZE)) {
              break;
          }
          if (0 == bdl::strcmp(buffer, "exit")) {
              break;
          }
          processLine(buffer);
      }
..
 At the end of this lexical scope 'managerGuard' is destroyed, releasing the
 default 'balm_MetricsManager' instance.
..
  }
..
 Next we define the 'processLine()' function.  The 'processLine()' function
 "processes" a line of text, and collects several metrics related to the
 function invocation.
..
  void processLine(const bdl::string& line)
      // Process the specified 'line' of text and write to standard output the
      // number of characters, words, and unique words in 'line'.
  {
..
 Increment the count of the number of calls to 'processLine()' and use the
 'BALM_METRICS_TIME_BLOCK' macro (see 'balm_metrics') to collect the elapsed
 time of this function call.  Note that all the metrics recorded by this
 function belong to the (arbitrarily chosen) category "Example".
..
      BALM_METRICS_INCREMENT("Example", "processLineCount");
      BALM_METRICS_TIME_BLOCK("Example",
                              "processLineElapsedTime",
                              balm_StopwatchScopedGuard::BALM_SECONDS);

      int                   wordCount  = 0;
      bdl::set<bdl::string> words;

      bdl::string        word;
      bdl::istringstream istream(line);
      while (istream >> word) {
          words.insert(word);
          ++wordCount;
      }

      bdl::cout << "Characters: count: " << line.size()
                << "\tWord count: " << wordCount
                << "\tUnique word count: " << words.size() << bdl::endl;

..
 Once we've "processed" the 'line', update the character count and word count
 metrics.
..
      BALM_METRICS_UPDATE("Example", "characterCount", line.size());
      BALM_METRICS_UPDATE("Example", "wordCount", wordCount);
  }
..
 We've now created our example application.  A typical session with this
 application might look like (note that '>' indicates user input):
..
 >this contains 4 words
   Characters: count: 21   Word count: 4   Unique word count: 4
 >this sentence contains 5 words
   Characters: count: 30   Word count: 5   Unique word count: 5
..
 Every 30 seconds metrics will be reported to standard output.  A typical
 publication of metrics would look like:
..
  17FEB2009_15:29:20.792+0000 4 Records
    Elapsed Time: 30.0092s
       Example.processLineCount [ count = 2, total = 2, min = 1, max = 1 ]
       Example.processLineElapsedTime [ count = 2, total = 0.0007656,
                                        min = 0.00022736, max = 0.00053824 ]
       Example.characterCount [ count = 2, total = 51, min = 21, max = 30 ]
       Example.wordCount [ count = 2, total = 9, min = 4, max = 5 ]
..

/Features Overview
/-----------------
 This section provides a brief summary of the features of the 'balm'
 package - details can be found in the indicated components and later in this
 document.

: o A protocol to provide pluggable publishing behavior.  Users can define and
:   register publishers with the metrics manager, which in turn defines the
:   behavior of the "publish" operation (see {'balm_publisher'})
:
: o A default (singleton) metrics manager instance (see
:   {'balm_defaultmetricsmanager'})
:
: o Simple macros for recording metrics to the default (singleton) metrics
:   manager instance (see {'balm_metrics'})
:
: o Simple types for recording metrics (see {'balm_metric'} and
:   {'balm_integermetric'})
:
: o A guard helper class for recording the elapsed time of a block of code to a
:   metric (see {'balm_stopwatchscopedguard'})
:
: o The ability to enable and disable the collection and publication of
:   categories of metrics (see {'balm_metricsmanager'} and {'balm_category'})
:
: o A scheduling mechanism for configuring the periodic publication of metrics
:   (see {'balm_publicationscheduler'})

/Multi-Threading
/---------------
 The components provided by the 'balm' package were designed for use in
 multi-threaded applications.  Metrics can be safely collected and published
 simultaneously from multiple threads.  Nevertheless, not every individual
 component in the 'balm' package is thread-safe.  See the individual component
 documentation for more information.

/Collecting Metrics
/------------------
 The 'balm' package defines several ways to collect metrics, as well as
 allowing users to define their own collection mechanisms.

/Choosing Between 'balm_metric' and 'balm_integermetric'
/- - - - - - - - - - - - - - - - - - - - - - - - - - - -
 The 'balm_metric' and 'balm_integermetric' components both define macros and
 helper classes for recording metrics.  The mechanisms in 'balm_integermetric'
 are slightly more efficient for collecting integral metric values, but are
 otherwise identical.

/Choosing Between Metric Collection Macros and Metric Collection Classes
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 The macros and classes defined by the 'balm_metric', 'balm_integermetric' and
 'balm_metrics' components provide the same basic functionality.  Clients may
 find the 'balm_Metric' or 'balm_IntegerMetric' classes better suited to
 collecting metrics associated with a particular instance of a stateful object,
 while the 'BALM_METRICS_*' macros are better suited to collecting metrics
 associated with a particular code path (rather than an object instance).  In
 most instances, however, choosing between the two is a matter of taste.

/Creating a User Defined Collection Mechanism
/ - - - - - - - - - - - - - - - - - - - - - -
 The 'balm' package allows users to define their own metric collection
 mechanisms by registering a callback with a 'balm_MetricsManager' object.
 User defined callbacks must match the
 'balm_MetricsManager::MetricsCollectionCallback' function signature and
 collect metrics for a *single* category.  Every time 'publish' is invoked for
 a category, the metrics manager will invoke the registered collection
 callbacks for that category, and publish the collected metrics.  See
 'balm_metricsmanager' for more information.

/Publishing Metrics
/------------------
 The 'balm_publisher' component defines a protocol for publishing metric
 records.  Users can register publisher objects with a metrics manager.
 Invoking 'publish()' on a metrics manager will collect metrics for the set of
 categories supplied with the function call, and then publish the metrics for
 each supplied category to publishers registered for that category.

 The 'balm_StreamPublisher' class implements the 'balm_Publisher' protocol to
 provide a default publisher for publishing metrics to a stream.

/Periodically Publishing Metrics
/-------------------------------
 Users can schedule the periodic publication of metrics using the
 'balm_publicationscheduler' component.  In the example presented above, under
 "Getting Started", a 'balm_PublicationScheduler' object was configured to
 publish all categories of metrics metrics every 30 seconds.

 At construction, a 'balm_PublicationScheduler' object is provided the
 addresses of a 'balm_MetricsManager' and a 'bcep_TimerEventScheduler'.  Users
 can call 'scheduleCategory()' to schedule an individual metric category to be
 published repeatedly at a given interval, or call 'setDefaultSchedule()' to
 schedule the publication of any category not given an individual schedule.  At
 the end of a scheduled time interval, the publication scheduler invokes the
 metrics manager's 'publish()' operation with the set of categories to publish.
 Note that, the publication scheduler will combine categories that occur at the
 same frequency into a single invocation of the metrics manager's 'publish'
 operation.

/Disabling Metric Categories
/---------------------------
 Users can disable (and re-enable) a category of metrics by calling
 'balm_MetricsManager::setCategoryEnabled' method.  A disabled category will
 not be published by the metrics manager.  In addition, the 'balm_metric',
 'balm_integermetric', 'balm_metrics', and 'balm_stopwatchscopedguard'
 components will not collect metrics for disabled categories (minimizing the
 performance cost of collecting metric for disabled categories).  Note that
 when 'balm_MetricsManager::publish()' is called on a disabled category, the
 metrics manager *will* invoke any user defined collection callbacks registered
 for the disable category, but *will* *not* publish the collected metrics.
 Users defining their own metrics collection mechanism (using a
 'balm_MetricsManager::MetricsCollectionCallback') must (manually) test whether
 a category is disabled if they wish to avoid collecting metrics for a disabled
 category.