// Copyright 2017 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. // // This file contains the declarations for the Metric class and related // types. #ifndef WVCDM_METRICS_COUNTER_METRIC_H_ #define WVCDM_METRICS_COUNTER_METRIC_H_ #include #include #include #include #include "attribute_handler.h" #include "field_tuples.h" #include "wv_metrics.pb.h" namespace wvcdm { namespace metrics { class CounterMetricTest; // This base class provides the common defintion used by all templated // instances of CounterMetric. class BaseCounterMetric { public: const std::map* GetValues() const { return &value_map_; }; protected: // Instantiates a BaseCounterMetric. BaseCounterMetric() {} virtual ~BaseCounterMetric() {} // Increment will look for an existing instance of the field names and // add the new value to the existing value. If the instance does not exist, // this method will create it. void Increment(const std::string& counter_key, int64_t value); private: friend class CounterMetricTest; const std::string metric_name_; // value_map_ contains a mapping from the field name/value pairs to the // counter(int64_t) instance. std::map value_map_; /* * This locks the internal state of the counter metric to ensure safety * across multiple threads preventing the caller from worrying about * locking. */ std::mutex internal_lock_; }; // The CounterMetric class is used to track a counter such as the number of // times a method is called. It can also track a delta that could be positive // or negative. // // The CounterMetric class supports the ability to keep track of multiple // variations of the count based on certain "field" values. E.g. keep track of // the counts of success and failure counts for a method call. Or keep track of // number of times the method was called with a particular parameter. // Fields define what variations to track. Each Field is a separate dimension. // The count for each combination of field values is tracked independently. // // Example usage: // // CounterMetric< // ::drm_metrics::Attributes::kErrorCodeFieldNumber, // CdmResponseType, // ::drm_metrics::Attributes::kCdmSecurityLevelFieldNumber, // CdmSecurityLevel> my_metric; // // // (counter value, error code, security level) // my_metric.Increment(1, CdmResponseType::NO_ERROR, SecurityLevel::kLevel3); // // The CounterMetric class serializes its values to a repeated field of // drm_metrics::CounterMetric instances. The field numbers used for // recording the drm_metrics::Attributes are specified in the template // parameters above (e.g. kErrorCodeFieldNumber). template class CounterMetric : public BaseCounterMetric { public: explicit CounterMetric() : BaseCounterMetric() {} // Increment will update the counter value associated with the provided // field values. void Increment(F1 field1 = util::Unused(), F2 field2 = util::Unused(), F3 field3 = util::Unused(), F4 field4 = util::Unused()) { Increment(1, field1, field2, field3, field4); } // Increment will add the value to the counter associated with the provided // field values. void Increment(int64_t value, F1 field1 = util::Unused(), F2 field2 = util::Unused(), F3 field3 = util::Unused(), F4 field4 = util::Unused()) { std::string key = attribute_handler_.GetSerializedAttributes( field1, field2, field3, field4); BaseCounterMetric::Increment(key, value); } void ToProto(::google::protobuf::RepeatedPtrField* counters) const; private: friend class CounterMetricTest; AttributeHandler attribute_handler_; }; // Partial specializations for CounterMetric template. // Specialization for the CounterMetric with no attributes. // For this, we don't deserialize and populate the attributes message. template <> inline void CounterMetric<0, util::Unused, 0, util::Unused, 0, util::Unused, 0, util::Unused>:: ToProto(::google::protobuf::RepeatedPtrField* counters) const { const std::map* values = GetValues(); for (std::map::const_iterator it = values->begin(); it != values->end(); it++) { drm_metrics::CounterMetric* new_counter = counters->Add(); new_counter->set_count(it->second); } } template inline void CounterMetric::ToProto( ::google::protobuf::RepeatedPtrField* counters) const { const std::map* values = GetValues(); for (std::map::const_iterator it = values->begin(); it != values->end(); it++) { drm_metrics::CounterMetric* new_counter = counters->Add(); if (!new_counter->mutable_attributes()->ParseFromString(it->first)) { LOGE("Failed to parse the attributes from a string."); } new_counter->set_count(it->second); } } } // namespace metrics } // namespace wvcdm #endif // WVCDM_METRICS_COUNTER_METRIC_H_