blob: 16c1e2af5c297a4cceda93c064d75cad5285cec1 [file] [log] [blame]
/*
* 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 <android/util/ProtoOutputStream.h>
#include <gtest/gtest_prod.h>
#include <kll.h>
#include <optional>
#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<std::unique_ptr<KllQuantile>, 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> configMetadataProvider);
inline MetricType getMetricType() const override {
return METRIC_TYPE_KLL;
}
protected:
private:
inline optional<int64_t> 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<int, HashableDimensionKey>& 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<KllQuantile>& 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<std::unique_ptr<KllQuantile>> buildPartialBucket(
int64_t bucketEndTime, std::vector<Interval>& intervals) override;
void writePastBucketAggregateToProto(const int aggIndex,
const std::unique_ptr<KllQuantile>& kll,
const int sampleSize,
ProtoOutputStream* const protoOutput) const override;
bool aggregateFields(const int64_t eventTimeNs, const MetricDimensionKey& eventKey,
const LogEvent& event, std::vector<Interval>& intervals,
Empty& empty) override;
// Internal function to calculate the current used bytes.
size_t byteSizeLocked() 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