1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <android/util/ProtoOutputStream.h> 20 #include <gtest/gtest_prod.h> 21 #include <kll.h> 22 23 #include <optional> 24 25 #include "MetricProducer.h" 26 #include "ValueMetricProducer.h" 27 #include "condition/ConditionTimer.h" 28 #include "condition/ConditionTracker.h" 29 #include "matchers/EventMatcherWizard.h" 30 #include "src/statsd_config.pb.h" 31 #include "stats_log_util.h" 32 33 using dist_proc::aggregation::KllQuantile; 34 35 namespace android { 36 namespace os { 37 namespace statsd { 38 39 // Uses KllQuantile to aggregate values within buckets. 40 // 41 // There are different events that might complete a bucket 42 // - a condition change 43 // - an app upgrade 44 // - an alarm set to the end of the bucket 45 class KllMetricProducer : public ValueMetricProducer<std::unique_ptr<KllQuantile>, Empty> { 46 public: 47 KllMetricProducer(const ConfigKey& key, const KllMetric& kllMetric, const uint64_t protoHash, 48 const PullOptions& pullOptions, const BucketOptions& bucketOptions, 49 const WhatOptions& whatOptions, const ConditionOptions& conditionOptions, 50 const StateOptions& stateOptions, const ActivationOptions& activationOptions, 51 const GuardrailOptions& guardrailOptions, 52 const wp<ConfigMetadataProvider> configMetadataProvider); 53 getMetricType()54 inline MetricType getMetricType() const override { 55 return METRIC_TYPE_KLL; 56 } 57 58 protected: 59 private: getConditionIdForMetric(const StatsdConfig & config,const int configIndex)60 inline optional<int64_t> getConditionIdForMetric(const StatsdConfig& config, 61 const int configIndex) const override { 62 const KllMetric& metric = config.kll_metric(configIndex); 63 return metric.has_condition() ? make_optional(metric.condition()) : nullopt; 64 } 65 getWhatAtomMatcherIdForMetric(const StatsdConfig & config,const int configIndex)66 inline int64_t getWhatAtomMatcherIdForMetric(const StatsdConfig& config, 67 const int configIndex) const override { 68 return config.kll_metric(configIndex).what(); 69 } 70 getConditionLinksForMetric(const StatsdConfig & config,const int configIndex)71 inline ConditionLinks getConditionLinksForMetric(const StatsdConfig& config, 72 const int configIndex) const override { 73 return config.kll_metric(configIndex).links(); 74 } 75 76 // Determine whether or not a LogEvent can be skipped. canSkipLogEventLocked(const MetricDimensionKey & eventKey,bool condition,int64_t eventTimeNs,const std::map<int,HashableDimensionKey> & statePrimaryKeys)77 inline bool canSkipLogEventLocked( 78 const MetricDimensionKey& eventKey, bool condition, int64_t eventTimeNs, 79 const std::map<int, HashableDimensionKey>& statePrimaryKeys) const override { 80 // Can only skip if the condition is false. 81 // We assume metric is pushed since KllMetric doesn't support pulled metrics. 82 return !condition; 83 } 84 85 DumpProtoFields getDumpProtoFields() const override; 86 aggregatedValueToString(const std::unique_ptr<KllQuantile> & aggregate)87 inline std::string aggregatedValueToString( 88 const std::unique_ptr<KllQuantile>& aggregate) const override { 89 return std::to_string(aggregate->num_values()) + " values"; 90 } 91 multipleBucketsSkipped(const int64_t numBucketsForward)92 inline bool multipleBucketsSkipped(const int64_t numBucketsForward) const override { 93 // Always false because we assume KllMetric is pushed only for now. 94 return false; 95 } 96 97 // The KllQuantile ptr ownership is transferred to newly created PastBuckets from Intervals. 98 PastBucket<std::unique_ptr<KllQuantile>> buildPartialBucket( 99 int64_t bucketEndTime, std::vector<Interval>& intervals) override; 100 101 void writePastBucketAggregateToProto(const int aggIndex, 102 const std::unique_ptr<KllQuantile>& kll, 103 const int sampleSize, 104 ProtoOutputStream* const protoOutput) const override; 105 106 size_t getAggregatedValueSize(const std::unique_ptr<KllQuantile>& kll) const override; 107 108 bool aggregateFields(const int64_t eventTimeNs, const MetricDimensionKey& eventKey, 109 const LogEvent& event, std::vector<Interval>& intervals, 110 Empty& empty) override; 111 112 // Internal function to calculate the current used bytes. 113 size_t byteSizeLocked() const override; 114 115 FRIEND_TEST(KllMetricProducerTest, TestByteSize); 116 FRIEND_TEST(KllMetricProducerTest, TestPushedEventsWithoutCondition); 117 FRIEND_TEST(KllMetricProducerTest, TestPushedEventsWithCondition); 118 FRIEND_TEST(KllMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket); 119 120 FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown); 121 FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall); 122 FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable); 123 124 FRIEND_TEST(KllMetricProducerTest_PartialBucket, TestPushedEventsMultipleBuckets); 125 126 FRIEND_TEST(ConfigUpdateTest, TestUpdateKllMetrics); 127 128 FRIEND_TEST(MetricsManagerUtilDimLimitTest, TestDimLimit); 129 130 FRIEND_TEST(ConfigUpdateDimLimitTest, TestDimLimit); 131 }; 132 133 } // namespace statsd 134 } // namespace os 135 } // namespace android 136