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

Commit 88588972 authored by Chenjie Yu's avatar Chenjie Yu
Browse files

allow statsd pull based on event trigger

Several restrictions:
1) This is only with GaugeMetric. We don't have use case for ValueMetric
to pull on event trigger.
2) trigger_event is set in the config. It can be generic atom matcher. But
we limit the number of atoms referenced in it to be 1. So we don't allow
multiple atoms to form a complex trigger.
3) This has to go with ALL_CONDITION_CHANGES sampling type.

+ also specify atom id of GaugeMetric output.

Bug: 111937835
Test: unit test
Change-Id: Ia15b1f209945f022edffb9ec5d673317d55d9e4f
parent e69a4919
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -31,9 +31,6 @@ namespace android {
namespace os {
namespace statsd {

// Util function to build a hard coded config with test metrics.
StatsdConfig build_fake_config();

/**
 * Keeps track of which configurations have been set from various sources.
 */
+10 −3
Original line number Diff line number Diff line
@@ -71,11 +71,14 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
                                         const int conditionIndex,
                                         const sp<ConditionWizard>& wizard, const int pullTagId,
                                         const int triggerAtomId, const int atomId,
                                         const int64_t timeBaseNs, const int64_t startTimeNs,
                                         const sp<StatsPullerManager>& pullerManager)
    : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
      mPullerManager(pullerManager),
      mPullTagId(pullTagId),
      mTriggerAtomId(triggerAtomId),
      mAtomId(atomId),
      mIsPulled(pullTagId != -1),
      mMinBucketSizeNs(metric.min_bucket_size_nanos()),
      mDimensionSoftLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
@@ -272,12 +275,12 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                    uint64_t atomsToken =
                        protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
                                           FIELD_ID_ATOM);
                    writeFieldValueTreeToStream(mTagId, *(atom.mFields), protoOutput);
                    writeFieldValueTreeToStream(mAtomId, *(atom.mFields), protoOutput);
                    protoOutput->end(atomsToken);
                }
                const bool truncateTimestamp =
                        android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.find(
                                mTagId) ==
                                mAtomId) ==
                        android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.end();
                for (const auto& atom : bucket.mGaugeAtoms) {
                    const int64_t elapsedTimestampNs =  truncateTimestamp ?
@@ -410,7 +413,6 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked(
        return;
    }
    int64_t eventTimeNs = event.GetElapsedTimestampNs();
    mTagId = event.GetTagId();
    if (eventTimeNs < mCurrentBucketStartTimeNs) {
        VLOG("Gauge Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
             (long long)mCurrentBucketStartTimeNs);
@@ -418,6 +420,11 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked(
    }
    flushIfNeededLocked(eventTimeNs);

    if (mTriggerAtomId == event.GetTagId()) {
        pullLocked(eventTimeNs);
        return;
    }

    // When gauge metric wants to randomly sample the output atom, we just simply use the first
    // gauge in the given bucket.
    if (mCurrentSlicedBucket->find(eventKey) != mCurrentSlicedBucket->end() &&
+9 −3
Original line number Diff line number Diff line
@@ -58,7 +58,8 @@ class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDa
public:
    GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
                        const int conditionIndex, const sp<ConditionWizard>& wizard,
                        const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
                        const int pullTagId, const int triggerAtomId, const int atomId,
                        const int64_t timeBaseNs, const int64_t startTimeNs,
                        const sp<StatsPullerManager>& pullerManager);

    virtual ~GaugeMetricProducer();
@@ -115,12 +116,16 @@ private:

    void pullLocked(const int64_t timestampNs);

    int mTagId;

    sp<StatsPullerManager> mPullerManager;
    // tagId for pulled data. -1 if this is not pulled
    const int mPullTagId;

    // tagId for atoms that trigger the pulling, if any
    const int mTriggerAtomId;

    // tagId for output atom
    const int mAtomId;

    // if this is pulled metric
    const bool mIsPulled;

@@ -169,6 +174,7 @@ private:
    FRIEND_TEST(GaugeMetricProducerTest, TestPulledWithUpgrade);
    FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection);
    FRIEND_TEST(GaugeMetricProducerTest, TestFirstBucket);
    FRIEND_TEST(GaugeMetricProducerTest, TestPullOnTrigger);
};

}  // namespace statsd
+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

#define DEBUG true  // STOPSHIP if true
#define DEBUG false  // STOPSHIP if true
#include "Log.h"

#include "ValueMetricProducer.h"
+42 −4
Original line number Diff line number Diff line
@@ -82,6 +82,28 @@ bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex,
    return true;
}

bool handlePullMetricTriggerWithLogTrackers(
        const int64_t trigger, const int metricIndex,
        const vector<sp<LogMatchingTracker>>& allAtomMatchers,
        const unordered_map<int64_t, int>& logTrackerMap,
        unordered_map<int, std::vector<int>>& trackerToMetricMap, int& logTrackerIndex) {
    auto logTrackerIt = logTrackerMap.find(trigger);
    if (logTrackerIt == logTrackerMap.end()) {
        ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)trigger);
        return false;
    }
    if (allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) {
        ALOGE("AtomMatcher \"%lld\" has more than one tag ids."
              "Trigger can only be one atom type.",
              (long long)trigger);
        return false;
    }
    logTrackerIndex = logTrackerIt->second;
    auto& metric_list = trackerToMetricMap[logTrackerIndex];
    metric_list.push_back(metricIndex);
    return true;
}

bool handleMetricWithConditions(
        const int64_t condition, const int metricIndex,
        const unordered_map<int64_t, int>& conditionTrackerMap,
@@ -502,13 +524,29 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
        }

        sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex);
        // If it is pulled atom, it should be simple matcher with one tagId.
        // For GaugeMetric atom, it should be simple matcher with one tagId.
        if (atomMatcher->getAtomIds().size() != 1) {
            return false;
        }
        int atomTagId = *(atomMatcher->getAtomIds().begin());
        int pullTagId = statsPullerManager.PullerForMatcherExists(atomTagId) ? atomTagId : -1;

        int triggerTrackerIndex;
        int triggerAtomId = -1;
        if (pullTagId != -1 && metric.has_trigger_event()) {
            // event_trigger should be used with ALL_CONDITION_CHANGES
            if (metric.sampling_type() != GaugeMetric::ALL_CONDITION_CHANGES) {
                return false;
            }
            if (!handlePullMetricTriggerWithLogTrackers(metric.trigger_event(), metricIndex,
                                                        allAtomMatchers, logTrackerMap,
                                                        trackerToMetricMap, triggerTrackerIndex)) {
                return false;
            }
            sp<LogMatchingTracker> triggerAtomMatcher = allAtomMatchers.at(triggerTrackerIndex);
            triggerAtomId = *(triggerAtomMatcher->getAtomIds().begin());
        }

        int conditionIndex = -1;
        if (metric.has_condition()) {
            bool good = handleMetricWithConditions(
@@ -524,8 +562,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
            }
        }

        sp<MetricProducer> gaugeProducer =
                new GaugeMetricProducer(key, metric, conditionIndex, wizard, pullTagId,
        sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
                key, metric, conditionIndex, wizard, pullTagId, triggerAtomId, atomTagId,
                timeBaseTimeNs, currentTimeNs, pullerManager);
        allMetricProducers.push_back(gaugeProducer);
    }
Loading