// Copyright 2017 Google Inc. All Rights Reserved. // // This file contains the declarations for the EventMetric class and related // types. #ifndef WVCDM_METRICS_EVENT_METRIC_H_ #define WVCDM_METRICS_EVENT_METRIC_H_ #include #include #include #include #include "distribution.h" #include "field_tuples.h" #include "lock.h" #include "metric_serialization.h" namespace wvcdm { namespace metrics { class EventMetricTest; // This base class provides the common defintion used by all templated // instances of EventMetric. class BaseEventMetric : public MetricSerializable { public: // Send metric values to the MetricSerializer. |serializer| must // not be null and is owned by the caller. virtual void Serialize(MetricSerializer* serializer); protected: // Instantiates a BaseEventMetric. BaseEventMetric(const std::string& metric_name) : metric_name_(metric_name) {} virtual ~BaseEventMetric(); // Record will look for an existing instance of the Distribution identified // by the field_names_values string and update it. If the instance does // not exist, this will create it. void Record(const std::string& field_names_values, double value); private: friend class EventMetricTest; const std::string metric_name_; // value_map_ contains a mapping from the field name/value pairs to the // distribution instance which holds the metric information (min, max, sum, // etc.). std::map value_map_; /* * This locks the internal state of the event metric to ensure safety across * multiple threads preventing the caller from worrying about locking. */ Lock internal_lock_; }; // This class converts the size_t value into the highest power of two // below the value. E.g. for 7, the value is 4. For 11, the value is 8. // This class is intended to simplify the use of EventMetric Fields that may // have many possible values, but we want to bucket them into a small set of // numbers (32 or 64). class Pow2Bucket { public: explicit Pow2Bucket(size_t value) : value_(GetLowerBucket(value)) {} Pow2Bucket(const Pow2Bucket& value) : value_(value.value_) {} // Support for converting to string. friend std::ostream& operator<<(std::ostream& os, const Pow2Bucket& log) { return os << log.value_; } private: inline size_t GetLowerBucket(size_t value) { if (!value) { return 0; } size_t log = 0; while (value) { log++; value >>= 1; } return 1u << (log - 1); } size_t value_; }; // The EventMetric class is used to capture statistics about an event such as // a method call. EventMetric keeps track of the count, mean, min, max and // variance for the value being measured. For example, we may want to track the // latency of a particular operation. Each time the operation is run, the time // is calculated and provided to the EventMetric by using the // EventMetric::Record method to capture and maintain statistics about the // latency (max, min, count, mean, variance). // // The EventMetric class supports the ability to breakdown the statistics based // on certain "field" values. For example, if a particular operation can run in // one of two modes, it's useful to track the latency of the operation in each // mode separately. You can use Fields to define how to breakdown the // statistics. Each Field is a separate dimension. The statistics for each // combination of field values are tracked independently. // // Example usage: // // EventMetric my_metric("multiple/fields/metric", // "request_type", "error_code", // Field names); // // my_metric.Record(1, 7, 23); // (latency value, request type, error code). // // The EventMetric supports serialization. A call to Serialize will // serialize all values to the provided MetricsSerializer instance. // // example: // // class MyMetricSerializer : public MetricSerializer { // // Add implementation here. // } // // MyMetricSerializer serializer; // my_metric.Serialize(&serializer); // template class EventMetric : public BaseEventMetric { public: // Create an EventMetric instance with the name |metric_name|. EventMetric(const std::string& metric_name); // Overloaded constructors with variable field name arguments. The number // of |field_name| arguments must match the number of used Field type // arguments. EventMetric(const std::string& metric_name, const char* field_name); EventMetric(const std::string& metric_name, const char* field_name1, const char* field_name2); EventMetric(const std::string& metric_name, const char* field_name1, const char* field_name2, const char* field_name3); EventMetric(const std::string& metric_name, const char* field_name1, const char* field_name2, const char* field_name3, const char* field_name4); // Record will update the statistics of the EventMetric broken down by the // given field values. void Record(double value, F1 field1 = util::Unused(), F2 field2 = util::Unused(), F3 field3 = util::Unused(), F4 field4 = util::Unused()); private: friend class EventMetricTest; std::vector field_names_; }; // Overloaded template constructor implementations for EventMetric. template EventMetric::EventMetric( const std::string& metric_name) : BaseEventMetric(metric_name) { ASSERT_METRIC_UNUSED_START_FROM(1); } template EventMetric::EventMetric( const std::string& metric_name, const char* field_name) : BaseEventMetric(metric_name) { ASSERT_METRIC_UNUSED_START_FROM(2); util::AppendFieldNames(&field_names_, util::FirstUnusedType::value - 1, field_name); } template EventMetric::EventMetric( const std::string& metric_name, const char* field_name1, const char* field_name2) : BaseEventMetric(metric_name) { ASSERT_METRIC_UNUSED_START_FROM(3); util::AppendFieldNames(&field_names_, util::FirstUnusedType::value - 1, field_name1, field_name2); } template EventMetric::EventMetric( const std::string& metric_name, const char* field_name1, const char* field_name2, const char* field_name3) : BaseEventMetric(metric_name) { ASSERT_METRIC_UNUSED_START_FROM(4); util::AppendFieldNames(&field_names_, util::FirstUnusedType::value - 1, field_name1, field_name2, field_name3); } template EventMetric::EventMetric( const std::string& metric_name, const char* field_name1, const char* field_name2, const char* field_name3, const char* field_name4) : BaseEventMetric(metric_name) { ASSERT_METRIC_UNUSED_START_FROM(5); util::AppendFieldNames(&field_names_, util::FirstUnusedType::value - 1, field_name1, field_name2, field_name3, field_name4); } template void EventMetric::Record( double value, F1 field1, F2 field2, F3 field3, F4 field4) { std::string field_name_values = util::MakeFieldNameString(field_names_, field1, field2, field3, field4); BaseEventMetric::Record(field_name_values, value); } } // namespace metrics } // namespace wvcdm #endif // WVCDM_METRICS_EVENT_METRIC_H_