/* * Copyright (C) 2021 The Android Open Source Project * * 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. */ #pragma once #include #include #include #include #include "MetricProducer.h" #include "ValueMetricProducer.h" #include "condition/ConditionTimer.h" #include "condition/ConditionTracker.h" #include "matchers/EventMatcherWizard.h" #include "src/statsd_config.pb.h" #include "stats_log_util.h" using dist_proc::aggregation::KllQuantile; namespace android { namespace os { namespace statsd { // Uses KllQuantile to aggregate values within buckets. // // There are different events that might complete a bucket // - a condition change // - an app upgrade // - an alarm set to the end of the bucket class KllMetricProducer : public ValueMetricProducer, Empty> { public: KllMetricProducer(const ConfigKey& key, const KllMetric& kllMetric, const uint64_t protoHash, const PullOptions& pullOptions, const BucketOptions& bucketOptions, const WhatOptions& whatOptions, const ConditionOptions& conditionOptions, const StateOptions& stateOptions, const ActivationOptions& activationOptions, const GuardrailOptions& guardrailOptions, const wp configMetadataProvider); inline MetricType getMetricType() const override { return METRIC_TYPE_KLL; } protected: private: inline optional getConditionIdForMetric(const StatsdConfig& config, const int configIndex) const override { const KllMetric& metric = config.kll_metric(configIndex); return metric.has_condition() ? make_optional(metric.condition()) : nullopt; } inline int64_t getWhatAtomMatcherIdForMetric(const StatsdConfig& config, const int configIndex) const override { return config.kll_metric(configIndex).what(); } inline ConditionLinks getConditionLinksForMetric(const StatsdConfig& config, const int configIndex) const override { return config.kll_metric(configIndex).links(); } // Determine whether or not a LogEvent can be skipped. inline bool canSkipLogEventLocked( const MetricDimensionKey& eventKey, bool condition, int64_t eventTimeNs, const std::map& statePrimaryKeys) const override { // Can only skip if the condition is false. // We assume metric is pushed since KllMetric doesn't support pulled metrics. return !condition; } DumpProtoFields getDumpProtoFields() const override; inline std::string aggregatedValueToString( const std::unique_ptr& aggregate) const override { return std::to_string(aggregate->num_values()) + " values"; } inline bool multipleBucketsSkipped(const int64_t numBucketsForward) const override { // Always false because we assume KllMetric is pushed only for now. return false; } // The KllQuantile ptr ownership is transferred to newly created PastBuckets from Intervals. PastBucket> buildPartialBucket( int64_t bucketEndTime, std::vector& intervals) override; void writePastBucketAggregateToProto(const int aggIndex, const std::unique_ptr& kll, const int sampleSize, ProtoOutputStream* const protoOutput) const override; size_t getAggregatedValueSize(const std::unique_ptr& kll) const override; bool aggregateFields(const int64_t eventTimeNs, const MetricDimensionKey& eventKey, const LogEvent& event, std::vector& intervals, Empty& empty) override; // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; DataCorruptionSeverity determineCorruptionSeverity(int32_t atomId, DataCorruptedReason reason, LostAtomType atomType) const override; FRIEND_TEST(KllMetricProducerTest, TestByteSize); FRIEND_TEST(KllMetricProducerTest, TestPushedEventsWithoutCondition); FRIEND_TEST(KllMetricProducerTest, TestPushedEventsWithCondition); FRIEND_TEST(KllMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket); FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown); FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall); FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable); FRIEND_TEST(KllMetricProducerTest_PartialBucket, TestPushedEventsMultipleBuckets); FRIEND_TEST(ConfigUpdateTest, TestUpdateKllMetrics); FRIEND_TEST(MetricsManagerUtilDimLimitTest, TestDimLimit); FRIEND_TEST(ConfigUpdateDimLimitTest, TestDimLimit); }; } // namespace statsd } // namespace os } // namespace android