Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9369446f authored by Yangster-mac's avatar Yangster-mac
Browse files

Support dimension in condition in metric producers.

Test: added e2e tests for count/duration metrics sliced by fields in condition and with/without links.

Change-Id: Ie34deba68e6780abdde458be3f0ce5284e76a1a2
parent 321ef3a5
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -165,6 +165,7 @@ LOCAL_CFLAGS += \

LOCAL_SRC_FILES := \
    $(statsd_common_src) \
    tests/dimension_test.cpp \
    tests/AnomalyMonitor_test.cpp \
    tests/anomaly/AnomalyTracker_test.cpp \
    tests/ConfigManager_test.cpp \
@@ -190,7 +191,8 @@ LOCAL_SRC_FILES := \
    tests/e2e/WakelockDuration_e2e_test.cpp \
    tests/e2e/MetricConditionLink_e2e_test.cpp \
    tests/e2e/Attribution_e2e_test.cpp \
    tests/e2e/GaugeMetric_e2e_test.cpp
    tests/e2e/GaugeMetric_e2e_test.cpp \
    tests/e2e/DimensionInCondition_e2e_test.cpp

LOCAL_STATIC_LIBRARIES := \
    $(statsd_common_static_libraries) \
+23 −3
Original line number Diff line number Diff line
@@ -67,12 +67,16 @@ android::hash_t hashDimensionsValue(const DimensionsValue& value) {
    return hashDimensionsValue(0, value);
}

android::hash_t hashMetricDimensionKey(int64_t seed, const MetricDimensionKey& dimensionKey) {
    android::hash_t hash = seed;
    hash = android::JenkinsHashMix(hash, std::hash<MetricDimensionKey>{}(dimensionKey));
    return JenkinsHashWhiten(hash);
}

using std::string;

string HashableDimensionKey::toString() const {
    string flattened;
    DimensionsValueToString(getDimensionsValue(), &flattened);
    return flattened;
    return DimensionsValueToString(getDimensionsValue());
}

bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) {
@@ -162,6 +166,22 @@ bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const {
    return LessThan(getDimensionsValue(), that.getDimensionsValue());
};

string MetricDimensionKey::toString() const {
    string flattened = mDimensionKeyInWhat.toString();
    flattened += mDimensionKeyInCondition.toString();
    return flattened;
}

bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const {
    return mDimensionKeyInWhat == that.getDimensionKeyInWhat() &&
        mDimensionKeyInCondition == that.getDimensionKeyInCondition();
};

bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const {
    return toString().compare(that.toString()) < 0;
};


}  // namespace statsd
}  // namespace os
}  // namespace android
 No newline at end of file
+60 −1
Original line number Diff line number Diff line
@@ -41,6 +41,10 @@ public:
        return mDimensionsValue;
    }

    inline DimensionsValue* getMutableDimensionsValue() {
        return &mDimensionsValue;
    }

    bool operator==(const HashableDimensionKey& that) const;

    bool operator<(const HashableDimensionKey& that) const;
@@ -53,8 +57,52 @@ private:
    DimensionsValue mDimensionsValue;
};

class MetricDimensionKey {
 public:
    explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat,
                                const HashableDimensionKey& dimensionKeyInCondition)
        : mDimensionKeyInWhat(dimensionKeyInWhat),
          mDimensionKeyInCondition(dimensionKeyInCondition) {};

    MetricDimensionKey(){};

    MetricDimensionKey(const MetricDimensionKey& that)
        : mDimensionKeyInWhat(that.getDimensionKeyInWhat()),
          mDimensionKeyInCondition(that.getDimensionKeyInCondition()) {};

    MetricDimensionKey& operator=(const MetricDimensionKey& from) = default;

    std::string toString() const;

    inline const HashableDimensionKey& getDimensionKeyInWhat() const {
        return mDimensionKeyInWhat;
    }

    inline const HashableDimensionKey& getDimensionKeyInCondition() const {
        return mDimensionKeyInCondition;
    }

    bool hasDimensionKeyInCondition() const {
        return mDimensionKeyInCondition.getDimensionsValue().has_field();
    }

    bool operator==(const MetricDimensionKey& that) const;

    bool operator<(const MetricDimensionKey& that) const;

    inline const char* c_str() const {
        return toString().c_str();
    }
  private:
      HashableDimensionKey mDimensionKeyInWhat;
      HashableDimensionKey mDimensionKeyInCondition;
};

bool compareDimensionsValue(const DimensionsValue& s1, const DimensionsValue& s2);

android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value);
android::hash_t hashDimensionsValue(const DimensionsValue& value);
android::hash_t hashMetricDimensionKey(int64_t see, const MetricDimensionKey& dimensionKey);

}  // namespace statsd
}  // namespace os
@@ -63,6 +111,7 @@ android::hash_t hashDimensionsValue(const DimensionsValue& value);
namespace std {

using android::os::statsd::HashableDimensionKey;
using android::os::statsd::MetricDimensionKey;

template <>
struct hash<HashableDimensionKey> {
@@ -71,4 +120,14 @@ struct hash<HashableDimensionKey> {
    }
};

template <>
struct hash<MetricDimensionKey> {
    std::size_t operator()(const MetricDimensionKey& key) const {
        android::hash_t hash = hashDimensionsValue(
            key.getDimensionKeyInWhat().getDimensionsValue());
        hash = android::JenkinsHashMix(hash,
                    hashDimensionsValue(key.getDimensionKeyInCondition().getDimensionsValue()));
        return android::JenkinsHashWhiten(hash);
    }
};
}  // namespace std
 No newline at end of file
+4 −1
Original line number Diff line number Diff line
@@ -104,7 +104,10 @@ private:
    FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
    FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);

    FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricNoLink);
    FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricWithLink);
    FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink);
    FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink);
};

}  // namespace statsd
+9 −9
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ void AnomalyTracker::flushPastBuckets(const int64_t& latestPastBucketNum) {
    }
}

void AnomalyTracker::addPastBucket(const HashableDimensionKey& key, const int64_t& bucketValue,
void AnomalyTracker::addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue,
                                   const int64_t& bucketNum) {
    flushPastBuckets(bucketNum);

@@ -147,7 +147,7 @@ void AnomalyTracker::addBucketToSum(const shared_ptr<DimToValMap>& bucket) {
    }
}

int64_t AnomalyTracker::getPastBucketValue(const HashableDimensionKey& key,
int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key,
                                           const int64_t& bucketNum) const {
    const auto& bucket = mPastBuckets[index(bucketNum)];
    if (bucket == nullptr) {
@@ -157,7 +157,7 @@ int64_t AnomalyTracker::getPastBucketValue(const HashableDimensionKey& key,
    return itr == bucket->end() ? 0 : itr->second;
}

int64_t AnomalyTracker::getSumOverPastBuckets(const HashableDimensionKey& key) const {
int64_t AnomalyTracker::getSumOverPastBuckets(const MetricDimensionKey& key) const {
    const auto& itr = mSumOverPastBuckets.find(key);
    if (itr != mSumOverPastBuckets.end()) {
        return itr->second;
@@ -165,7 +165,7 @@ int64_t AnomalyTracker::getSumOverPastBuckets(const HashableDimensionKey& key) c
    return 0;
}

bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const HashableDimensionKey& key,
bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const MetricDimensionKey& key,
                                   const int64_t& currentBucketValue) {
    if (currentBucketNum > mMostRecentBucketNum + 1) {
        // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this.
@@ -175,7 +175,7 @@ bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const Hashab
            && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
}

void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const HashableDimensionKey& key) {
void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key) {
    // TODO: Why receive timestamp? RefractoryPeriod should always be based on real time right now.
    if (isInRefractoryPeriod(timestampNs, key)) {
        VLOG("Skipping anomaly declaration since within refractory period");
@@ -199,14 +199,14 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const HashableD

    StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());

    // TODO: This should also take in the const HashableDimensionKey& key?
    // TODO: This should also take in the const MetricDimensionKey& key?
    android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(),
                               mConfigKey.GetId(), mAlert.id());
}

void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
                                             const int64_t& currBucketNum,
                                             const HashableDimensionKey& key,
                                             const MetricDimensionKey& key,
                                             const int64_t& currentBucketValue) {
    if (detectAnomaly(currBucketNum, key, currentBucketValue)) {
        declareAnomaly(timestampNs, key);
@@ -214,7 +214,7 @@ void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
}

bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs,
                                          const HashableDimensionKey& key) {
                                          const MetricDimensionKey& key) {
    const auto& it = mRefractoryPeriodEndsSec.find(key);
    if (it != mRefractoryPeriodEndsSec.end()) {
        if ((timestampNs / NS_PER_SEC) <= it->second) {
@@ -226,7 +226,7 @@ bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs,
    return false;
}

void AnomalyTracker::informSubscribers(const HashableDimensionKey& key) {
void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) {
    VLOG("informSubscribers called.");
    if (mSubscriptions.empty()) {
        ALOGE("Attempt to call with no subscribers.");
Loading