diff options
Diffstat (limited to 'statsd/src')
-rw-r--r-- | statsd/src/FieldValue.cpp | 11 | ||||
-rw-r--r-- | statsd/src/FieldValue.h | 2 | ||||
-rw-r--r-- | statsd/src/StatsLogProcessor.h | 2 | ||||
-rw-r--r-- | statsd/src/guardrail/stats_log_enums.proto | 2 | ||||
-rw-r--r-- | statsd/src/metrics/MetricsManager.h | 2 | ||||
-rw-r--r-- | statsd/src/metrics/NumericValueMetricProducer.cpp | 14 | ||||
-rw-r--r-- | statsd/src/metrics/NumericValueMetricProducer.h | 15 | ||||
-rw-r--r-- | statsd/src/metrics/ValueMetricProducer.h | 1 | ||||
-rw-r--r-- | statsd/src/metrics/parsing_utils/metrics_manager_util.cpp | 32 | ||||
-rw-r--r-- | statsd/src/statsd_config.proto | 2 |
10 files changed, 71 insertions, 12 deletions
diff --git a/statsd/src/FieldValue.cpp b/statsd/src/FieldValue.cpp index aa129a44..84fad927 100644 --- a/statsd/src/FieldValue.cpp +++ b/statsd/src/FieldValue.cpp @@ -60,6 +60,17 @@ bool Field::matches(const Matcher& matcher) const { return false; } +std::vector<Matcher> dedupFieldMatchers(const std::vector<Matcher>& fieldMatchers) { + std::vector<Matcher> dedupedFieldMatchers; + for (size_t i = 0; i < fieldMatchers.size(); i++) { + if (std::find(dedupedFieldMatchers.begin(), dedupedFieldMatchers.end(), fieldMatchers[i]) == + dedupedFieldMatchers.end()) { + dedupedFieldMatchers.push_back(fieldMatchers[i]); + } + } + return dedupedFieldMatchers; +} + void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* pos, int* mask, std::vector<Matcher>* output) { if (depth > kMaxLogDepth) { diff --git a/statsd/src/FieldValue.h b/statsd/src/FieldValue.h index 2ac71cb8..66b54755 100644 --- a/statsd/src/FieldValue.h +++ b/statsd/src/FieldValue.h @@ -463,6 +463,8 @@ bool isAttributionUidField(const FieldValue& value); /* returns uid if the field is uid field, or -1 if the field is not a uid field */ int getUidIfExists(const FieldValue& value); +std::vector<Matcher> dedupFieldMatchers(const std::vector<Matcher>& fieldMatchers); + void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output); bool isAttributionUidField(const Field& field, const Value& value); diff --git a/statsd/src/StatsLogProcessor.h b/statsd/src/StatsLogProcessor.h index c1c7dd63..b6d66af9 100644 --- a/statsd/src/StatsLogProcessor.h +++ b/statsd/src/StatsLogProcessor.h @@ -485,6 +485,8 @@ private: FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions); FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions); FRIEND_TEST(ValueMetricE2eTest, TestInitWithValueFieldPositionALL); + FRIEND_TEST(ValueMetricE2eTest, TestInitWithMultipleAggTypes); + FRIEND_TEST(ValueMetricE2eTest, TestInitWithDefaultAggType); FRIEND_TEST(KllMetricE2eTest, TestInitWithKllFieldPositionALL); diff --git a/statsd/src/guardrail/stats_log_enums.proto b/statsd/src/guardrail/stats_log_enums.proto index 7b4c79a4..c468d52e 100644 --- a/statsd/src/guardrail/stats_log_enums.proto +++ b/statsd/src/guardrail/stats_log_enums.proto @@ -151,6 +151,8 @@ enum InvalidConfigReasonEnum { INVALID_CONFIG_REASON_METRIC_INCORRECT_PULL_PROBABILITY = 93; INVALID_CONFIG_REASON_GAUGE_METRIC_PUSHED_WITH_PULL_PROBABILITY = 94; INVALID_CONFIG_REASON_GAUGE_METRIC_RANDOM_ONE_SAMPLE_WITH_PULL_PROBABILITY = 95; + INVALID_CONFIG_REASON_VALUE_METRIC_DEFINES_SINGLE_AND_MULTIPLE_AGG_TYPES = 96; + INVALID_CONFIG_REASON_VALUE_METRIC_AGG_TYPES_DNE_VALUE_FIELDS_SIZE = 97; }; enum InvalidQueryReason { diff --git a/statsd/src/metrics/MetricsManager.h b/statsd/src/metrics/MetricsManager.h index 2072d61b..4ccee562 100644 --- a/statsd/src/metrics/MetricsManager.h +++ b/statsd/src/metrics/MetricsManager.h @@ -437,6 +437,8 @@ private: FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState); FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions); FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions); + FRIEND_TEST(ValueMetricE2eTest, TestInitWithMultipleAggTypes); + FRIEND_TEST(ValueMetricE2eTest, TestInitWithDefaultAggType); }; } // namespace statsd diff --git a/statsd/src/metrics/NumericValueMetricProducer.cpp b/statsd/src/metrics/NumericValueMetricProducer.cpp index 4024ccef..88c4d16e 100644 --- a/statsd/src/metrics/NumericValueMetricProducer.cpp +++ b/statsd/src/metrics/NumericValueMetricProducer.cpp @@ -22,6 +22,7 @@ #include <limits.h> #include <stdlib.h> +#include "FieldValue.h" #include "guardrail/StatsdStats.h" #include "metrics/parsing_utils/metrics_manager_util.h" #include "stats_log_util.h" @@ -70,7 +71,7 @@ NumericValueMetricProducer::NumericValueMetricProducer( : ValueMetricProducer(metric.id(), key, protoHash, pullOptions, bucketOptions, whatOptions, conditionOptions, stateOptions, activationOptions, guardrailOptions), mUseAbsoluteValueOnReset(metric.use_absolute_value_on_reset()), - mAggregationType(metric.aggregation_type()), + mAggregationTypes(whatOptions.aggregationTypes), mIncludeSampleSize(metric.has_include_sample_size() ? metric.include_sample_size() : metric.aggregation_type() == ValueMetric_AggregationType_AVG), @@ -80,7 +81,8 @@ NumericValueMetricProducer::NumericValueMetricProducer( mUseZeroDefaultBase(metric.use_zero_default_base()), mHasGlobalBase(false), mMaxPullDelayNs(metric.has_max_pull_delay_sec() ? metric.max_pull_delay_sec() * NS_PER_SEC - : StatsdStats::kPullMaxDelayNs) { + : StatsdStats::kPullMaxDelayNs), + mDedupedFieldMatchers(dedupFieldMatchers(whatOptions.fieldMatchers)) { // TODO(b/186677791): Use initializer list to initialize mUploadThreshold. if (metric.has_threshold()) { mUploadThreshold = metric.threshold(); @@ -274,9 +276,9 @@ void NumericValueMetricProducer::accumulateEvents(const vector<shared_ptr<LogEve // Get dimensions_in_what key and value indices. HashableDimensionKey dimensionsInWhat; - vector<int> valueIndices(mFieldMatchers.size(), -1); + vector<int> valueIndices(mDedupedFieldMatchers.size(), -1); const LogEvent& eventRef = transformedEvent == nullptr ? *data : *transformedEvent; - if (!filterValues(mDimensionsInWhat, mFieldMatchers, eventRef.getValues(), + if (!filterValues(mDimensionsInWhat, mDedupedFieldMatchers, eventRef.getValues(), dimensionsInWhat, valueIndices)) { StatsdStats::getInstance().noteBadValueType(mMetricId); } @@ -478,7 +480,7 @@ bool NumericValueMetricProducer::aggregateFields(const int64_t eventTimeNs, } if (interval.hasValue()) { - switch (mAggregationType) { + switch (getAggregationTypeLocked(i)) { case ValueMetric::SUM: // for AVG, we add up and take average when flushing the bucket case ValueMetric::AVG: @@ -664,7 +666,7 @@ bool NumericValueMetricProducer::valuePassesThreshold(const Interval& interval) } Value NumericValueMetricProducer::getFinalValue(const Interval& interval) const { - if (mAggregationType != ValueMetric::AVG) { + if (getAggregationTypeLocked(interval.aggIndex) != ValueMetric::AVG) { return interval.aggregate; } else { double sum = interval.aggregate.type == LONG ? (double)interval.aggregate.long_value diff --git a/statsd/src/metrics/NumericValueMetricProducer.h b/statsd/src/metrics/NumericValueMetricProducer.h index 775fc1af..9c123f64 100644 --- a/statsd/src/metrics/NumericValueMetricProducer.h +++ b/statsd/src/metrics/NumericValueMetricProducer.h @@ -142,12 +142,16 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; - void combineValueFields(pair<LogEvent, vector<int>>& eventValues, const LogEvent& newEvent, - const vector<int>& newValueIndices) const; + void combineValueFields(pair<LogEvent, std::vector<int>>& eventValues, const LogEvent& newEvent, + const std::vector<int>& newValueIndices) const; + + ValueMetric::AggregationType getAggregationTypeLocked(int index) const { + return mAggregationTypes.size() == 1 ? mAggregationTypes[0] : mAggregationTypes[index]; + } const bool mUseAbsoluteValueOnReset; - const ValueMetric::AggregationType mAggregationType; + const std::vector<ValueMetric::AggregationType> mAggregationTypes; const bool mIncludeSampleSize; @@ -171,6 +175,9 @@ private: const int64_t mMaxPullDelayNs; + // Deduped value fields for matching. + const std::vector<Matcher> mDedupedFieldMatchers; + // For anomaly detection. std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket; @@ -232,6 +239,8 @@ private: FRIEND_TEST(NumericValueMetricProducerTest, TestSlicedStateWithMultipleDimensionsMissingDataInPull); FRIEND_TEST(NumericValueMetricProducerTest, TestUploadThreshold); + FRIEND_TEST(NumericValueMetricProducerTest, TestMultipleAggTypesPulled); + FRIEND_TEST(NumericValueMetricProducerTest, TestMultipleAggTypesPushed); FRIEND_TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed); FRIEND_TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed); diff --git a/statsd/src/metrics/ValueMetricProducer.h b/statsd/src/metrics/ValueMetricProducer.h index 92541029..d10fc091 100644 --- a/statsd/src/metrics/ValueMetricProducer.h +++ b/statsd/src/metrics/ValueMetricProducer.h @@ -88,6 +88,7 @@ public: const sp<EventMatcherWizard>& matcherWizard; const FieldMatcher& dimensionsInWhat; const vector<Matcher>& fieldMatchers; + const vector<ValueMetric::AggregationType> aggregationTypes; }; struct ConditionOptions { diff --git a/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp index f0c5bb25..dfdcc65f 100644 --- a/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp +++ b/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp @@ -922,6 +922,27 @@ optional<sp<MetricProducer>> createNumericValueMetricProducerAndUpdateMetadata( return nullopt; } + std::vector<ValueMetric::AggregationType> aggregationTypes; + if (metric.aggregation_types_size() != 0) { + if (metric.has_aggregation_type()) { + invalidConfigReason = InvalidConfigReason( + INVALID_CONFIG_REASON_VALUE_METRIC_DEFINES_SINGLE_AND_MULTIPLE_AGG_TYPES, + metric.id()); + return nullopt; + } + if (metric.aggregation_types_size() != (int)fieldMatchers.size()) { + invalidConfigReason = InvalidConfigReason( + INVALID_CONFIG_REASON_VALUE_METRIC_AGG_TYPES_DNE_VALUE_FIELDS_SIZE, + metric.id()); + return nullopt; + } + for (int i = 0; i < metric.aggregation_types_size(); i++) { + aggregationTypes.push_back(metric.aggregation_types(i)); + } + } else { // aggregation_type() is set or default is used. + aggregationTypes.push_back(metric.aggregation_type()); + } + int trackerIndex; invalidConfigReason = handleMetricWithAtomMatchingTrackers( metric.what(), metric.id(), metricIndex, @@ -1019,7 +1040,7 @@ optional<sp<MetricProducer>> createNumericValueMetricProducerAndUpdateMetadata( {timeBaseNs, currentTimeNs, bucketSizeNs, metric.min_bucket_size_nanos(), conditionCorrectionThresholdNs, getAppUpgradeBucketSplit(metric)}, {containsAnyPositionInDimensionsInWhat, shouldUseNestedDimensions, trackerIndex, - matcherWizard, metric.dimensions_in_what(), fieldMatchers}, + matcherWizard, metric.dimensions_in_what(), fieldMatchers, aggregationTypes}, {conditionIndex, metric.links(), initialConditionCache, wizard}, {metric.state_link(), slicedStateAtoms, stateGroupMap}, {eventActivationMap, eventDeactivationMap}, {dimensionSoftLimit, dimensionHardLimit}); @@ -1171,8 +1192,13 @@ optional<sp<MetricProducer>> createKllMetricProducerAndUpdateMetadata( key, metric, metricHash, {/*pullTagId=*/-1, pullerManager}, {timeBaseNs, currentTimeNs, bucketSizeNs, metric.min_bucket_size_nanos(), /*conditionCorrectionThresholdNs=*/nullopt, getAppUpgradeBucketSplit(metric)}, - {containsAnyPositionInDimensionsInWhat, shouldUseNestedDimensions, trackerIndex, - matcherWizard, metric.dimensions_in_what(), fieldMatchers}, + {containsAnyPositionInDimensionsInWhat, + shouldUseNestedDimensions, + trackerIndex, + matcherWizard, + metric.dimensions_in_what(), + fieldMatchers, + {}}, {conditionIndex, metric.links(), initialConditionCache, wizard}, {metric.state_link(), slicedStateAtoms, stateGroupMap}, {eventActivationMap, eventDeactivationMap}, {dimensionSoftLimit, dimensionHardLimit}); diff --git a/statsd/src/statsd_config.proto b/statsd/src/statsd_config.proto index b49d3e89..cbd60ee3 100644 --- a/statsd/src/statsd_config.proto +++ b/statsd/src/statsd_config.proto @@ -395,6 +395,8 @@ message ValueMetric { } optional AggregationType aggregation_type = 8 [default = SUM]; + repeated AggregationType aggregation_types = 25; + optional bool include_sample_size = 22; optional int64 min_bucket_size_nanos = 10; |