1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.cts.statsd.alert; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static com.google.common.truth.Truth.assertWithMessage; 20 21 import android.cts.statsd.atom.AtomTestCase; 22 23 import com.android.internal.os.StatsdConfigProto; 24 import com.android.internal.os.StatsdConfigProto.Alert; 25 import com.android.internal.os.StatsdConfigProto.CountMetric; 26 import com.android.internal.os.StatsdConfigProto.DurationMetric; 27 import com.android.internal.os.StatsdConfigProto.FieldFilter; 28 import com.android.internal.os.StatsdConfigProto.FieldMatcher; 29 import com.android.internal.os.StatsdConfigProto.GaugeMetric; 30 import com.android.internal.os.StatsdConfigProto.IncidentdDetails; 31 import com.android.internal.os.StatsdConfigProto.PerfettoDetails; 32 import com.android.internal.os.StatsdConfigProto.StatsdConfig; 33 import com.android.internal.os.StatsdConfigProto.Subscription; 34 import com.android.internal.os.StatsdConfigProto.TimeUnit; 35 import com.android.internal.os.StatsdConfigProto.ValueMetric; 36 import com.android.os.AtomsProto.AnomalyDetected; 37 import com.android.os.AtomsProto.AppBreadcrumbReported; 38 import com.android.os.AtomsProto.Atom; 39 import com.android.os.AtomsProto.DebugElapsedClock; 40 import com.android.os.StatsLog.EventMetricData; 41 import com.android.tradefed.log.LogUtil.CLog; 42 import java.util.List; 43 44 /** 45 * Statsd Anomaly Detection tests. 46 */ 47 public class AnomalyDetectionTests extends AtomTestCase { 48 49 private static final String TAG = "Statsd.AnomalyDetectionTests"; 50 51 private static final boolean INCIDENTD_TESTS_ENABLED = false; 52 private static final boolean PERFETTO_TESTS_ENABLED = true; 53 54 private static final int WAIT_AFTER_BREADCRUMB_MS = 2000; 55 56 // Config constants 57 private static final int APP_BREADCRUMB_REPORTED_MATCH_START_ID = 1; 58 private static final int APP_BREADCRUMB_REPORTED_MATCH_STOP_ID = 2; 59 private static final int METRIC_ID = 8; 60 private static final int ALERT_ID = 11; 61 private static final int SUBSCRIPTION_ID_INCIDENTD = 41; 62 private static final int SUBSCRIPTION_ID_PERFETTO = 42; 63 private static final int ANOMALY_DETECT_MATCH_ID = 10; 64 private static final int ANOMALY_EVENT_ID = 101; 65 private static final int INCIDENTD_SECTION = -1; 66 67 @Override setUp()68 protected void setUp() throws Exception { 69 super.setUp(); 70 if (!INCIDENTD_TESTS_ENABLED) { 71 CLog.w(TAG, TAG + " anomaly tests are disabled by a flag. Change flag to true to run"); 72 } 73 } 74 75 @Override tearDown()76 protected void tearDown() throws Exception { 77 super.tearDown(); 78 if (PERFETTO_TESTS_ENABLED) { 79 //Deadline to finish trace collection 80 final long deadLine = System.currentTimeMillis() + 10000; 81 while (isSystemTracingEnabled()) { 82 if (System.currentTimeMillis() > deadLine) { 83 CLog.w("/sys/kernel/debug/tracing/tracing_on is still 1 after 10 secs : " + isSystemTracingEnabled()); 84 break; 85 } 86 CLog.d("Waiting to finish collecting traces. "); 87 Thread.sleep(WAIT_TIME_SHORT); 88 } 89 } 90 } 91 92 // Tests that anomaly detection for count works. 93 // Also tests that anomaly detection works when spanning multiple buckets. testCountAnomalyDetection()94 public void testCountAnomalyDetection() throws Exception { 95 StatsdConfig.Builder config = getBaseConfig(10, 20, 2 /* threshold: > 2 counts */) 96 .addCountMetric(CountMetric.newBuilder() 97 .setId(METRIC_ID) 98 .setWhat(APP_BREADCRUMB_REPORTED_MATCH_START_ID) 99 .setBucket(TimeUnit.CTS) // 1 second 100 // Slice by label 101 .setDimensionsInWhat(FieldMatcher.newBuilder() 102 .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER) 103 .addChild(FieldMatcher.newBuilder() 104 .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER) 105 ) 106 ) 107 ); 108 uploadConfig(config); 109 110 String markTime = getCurrentLogcatDate(); 111 // count(label=6) -> 1 (not an anomaly, since not "greater than 2") 112 doAppBreadcrumbReportedStart(6); 113 Thread.sleep(500); 114 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 115 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse(); 116 117 // count(label=6) -> 2 (not an anomaly, since not "greater than 2") 118 doAppBreadcrumbReportedStart(6); 119 Thread.sleep(500); 120 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 121 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse(); 122 123 // count(label=12) -> 1 (not an anomaly, since not "greater than 2") 124 doAppBreadcrumbReportedStart(12); 125 Thread.sleep(1000); 126 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 127 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse(); 128 129 doAppBreadcrumbReportedStart(6); // count(label=6) -> 3 (anomaly, since "greater than 2"!) 130 Thread.sleep(WAIT_AFTER_BREADCRUMB_MS); 131 132 List<EventMetricData> data = getEventMetricDataList(); 133 assertWithMessage("Expected anomaly").that(data).hasSize(1); 134 assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID); 135 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue(); 136 } 137 138 // Tests that anomaly detection for duration works. 139 // Also tests that refractory periods in anomaly detection work. testDurationAnomalyDetection()140 public void testDurationAnomalyDetection() throws Exception { 141 final int APP_BREADCRUMB_REPORTED_IS_ON_PREDICATE = 1423; 142 StatsdConfig.Builder config = 143 getBaseConfig(17, 17, 10_000_000_000L /*threshold: > 10 seconds in nanoseconds*/) 144 .addDurationMetric(DurationMetric.newBuilder() 145 .setId(METRIC_ID) 146 .setWhat(APP_BREADCRUMB_REPORTED_IS_ON_PREDICATE) // predicate below 147 .setAggregationType(DurationMetric.AggregationType.SUM) 148 .setBucket(TimeUnit.CTS) // 1 second 149 ) 150 .addPredicate(StatsdConfigProto.Predicate.newBuilder() 151 .setId(APP_BREADCRUMB_REPORTED_IS_ON_PREDICATE) 152 .setSimplePredicate(StatsdConfigProto.SimplePredicate.newBuilder() 153 .setStart(APP_BREADCRUMB_REPORTED_MATCH_START_ID) 154 .setStop(APP_BREADCRUMB_REPORTED_MATCH_STOP_ID) 155 ) 156 ); 157 uploadConfig(config); 158 159 // Since timing is crucial and checking logcat for incidentd is slow, we don't test for it. 160 161 // Test that alarm doesn't fire early. 162 String markTime = getCurrentLogcatDate(); 163 doAppBreadcrumbReportedStart(1); 164 Thread.sleep(6_000); // Recorded duration at end: 6s 165 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 166 167 doAppBreadcrumbReportedStop(1); 168 Thread.sleep(4_000); // Recorded duration at end: 6s 169 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 170 171 // Test that alarm does fire when it is supposed to (after 4s, plus up to 5s alarm delay). 172 doAppBreadcrumbReportedStart(1); 173 Thread.sleep(9_000); // Recorded duration at end: 13s 174 doAppBreadcrumbReported(2); 175 List<EventMetricData> data = getEventMetricDataList(); 176 assertWithMessage("Expected anomaly").that(data).hasSize(1); 177 assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID); 178 179 // Now test that the refractory period is obeyed. 180 markTime = getCurrentLogcatDate(); 181 doAppBreadcrumbReportedStop(1); 182 doAppBreadcrumbReportedStart(1); 183 Thread.sleep(3_000); // Recorded duration at end: 13s 184 // NB: the previous getEventMetricDataList also removes the report, so size is back to 0. 185 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 186 187 // Test that detection works again after refractory period finishes. 188 doAppBreadcrumbReportedStop(1); 189 Thread.sleep(8_000); // Recorded duration at end: 9s 190 doAppBreadcrumbReportedStart(1); 191 Thread.sleep(15_000); // Recorded duration at end: 15s 192 // We can do an incidentd test now that all the timing issues are done. 193 doAppBreadcrumbReported(2); 194 data = getEventMetricDataList(); 195 assertWithMessage("Expected anomaly").that(data).hasSize(1); 196 assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID); 197 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue(); 198 199 doAppBreadcrumbReportedStop(1); 200 } 201 202 // Tests that anomaly detection for duration works even when the alarm fires too late. testDurationAnomalyDetectionForLateAlarms()203 public void testDurationAnomalyDetectionForLateAlarms() throws Exception { 204 final int APP_BREADCRUMB_REPORTED_IS_ON_PREDICATE = 1423; 205 StatsdConfig.Builder config = 206 getBaseConfig(50, 0, 6_000_000_000L /* threshold: > 6 seconds in nanoseconds */) 207 .addDurationMetric(DurationMetric.newBuilder() 208 .setId(METRIC_ID) 209 .setWhat( 210 APP_BREADCRUMB_REPORTED_IS_ON_PREDICATE) // Predicate below. 211 .setAggregationType(DurationMetric.AggregationType.SUM) 212 .setBucket(TimeUnit.CTS) // 1 second 213 ) 214 .addPredicate(StatsdConfigProto.Predicate.newBuilder() 215 .setId(APP_BREADCRUMB_REPORTED_IS_ON_PREDICATE) 216 .setSimplePredicate(StatsdConfigProto.SimplePredicate.newBuilder() 217 .setStart(APP_BREADCRUMB_REPORTED_MATCH_START_ID) 218 .setStop(APP_BREADCRUMB_REPORTED_MATCH_STOP_ID) 219 ) 220 ); 221 uploadConfig(config); 222 223 doAppBreadcrumbReportedStart(1); 224 Thread.sleep(5_000); 225 doAppBreadcrumbReportedStop(1); 226 Thread.sleep(2_000); 227 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 228 229 // Test that alarm does fire when it is supposed to. 230 // The anomaly occurs in 1s, but alarms won't fire that quickly. 231 // It is likely that the alarm will only fire after this period is already over, but the 232 // anomaly should nonetheless be detected when the event stops. 233 doAppBreadcrumbReportedStart(1); 234 Thread.sleep(1_200); 235 // Anomaly should be detected here if the alarm didn't fire yet. 236 doAppBreadcrumbReportedStop(1); 237 Thread.sleep(200); 238 List<EventMetricData> data = getEventMetricDataList(); 239 if (data.size() == 2) { 240 // Although we expect that the alarm won't fire, we certainly cannot demand that. 241 CLog.w(TAG, "The anomaly was detected twice. Presumably the alarm did manage to fire."); 242 } 243 assertThat(data.size()).isAnyOf(1, 2); 244 assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID); 245 } 246 247 // Tests that anomaly detection for value works. testValueAnomalyDetection()248 public void testValueAnomalyDetection() throws Exception { 249 StatsdConfig.Builder config = getBaseConfig(4, 0, 6 /* threshold: value > 6 */) 250 .addValueMetric(ValueMetric.newBuilder() 251 .setId(METRIC_ID) 252 .setWhat(APP_BREADCRUMB_REPORTED_MATCH_START_ID) 253 .setBucket(TimeUnit.ONE_MINUTE) 254 // Get the label field's value: 255 .setValueField(FieldMatcher.newBuilder() 256 .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER) 257 .addChild(FieldMatcher.newBuilder() 258 .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)) 259 ) 260 261 ); 262 uploadConfig(config); 263 264 String markTime = getCurrentLogcatDate(); 265 doAppBreadcrumbReportedStart(6); // value = 6, which is NOT > trigger 266 Thread.sleep(WAIT_AFTER_BREADCRUMB_MS); 267 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 268 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse(); 269 270 doAppBreadcrumbReportedStart(14); // value = 14 > trigger 271 Thread.sleep(WAIT_AFTER_BREADCRUMB_MS); 272 273 List<EventMetricData> data = getEventMetricDataList(); 274 assertWithMessage("Expected anomaly").that(data).hasSize(1); 275 assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID); 276 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue(); 277 } 278 279 // Test that anomaly detection integrates with perfetto properly. testPerfetto()280 public void testPerfetto() throws Exception { 281 String chars = getDevice().getProperty("ro.build.characteristics"); 282 if (chars.contains("watch")) { 283 return; 284 } 285 286 if (PERFETTO_TESTS_ENABLED) resetPerfettoGuardrails(); 287 288 StatsdConfig.Builder config = getBaseConfig(4, 0, 6 /* threshold: value > 6 */) 289 .addSubscription(Subscription.newBuilder() 290 .setId(SUBSCRIPTION_ID_PERFETTO) 291 .setRuleType(Subscription.RuleType.ALERT) 292 .setRuleId(ALERT_ID) 293 .setPerfettoDetails(PerfettoDetails.newBuilder() 294 .setTraceConfig(getPerfettoConfig())) 295 ) 296 .addValueMetric(ValueMetric.newBuilder() 297 .setId(METRIC_ID) 298 .setWhat(APP_BREADCRUMB_REPORTED_MATCH_START_ID) 299 .setBucket(TimeUnit.ONE_MINUTE) 300 // Get the label field's value: 301 .setValueField(FieldMatcher.newBuilder() 302 .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER) 303 .addChild(FieldMatcher.newBuilder() 304 .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)) 305 ) 306 307 ); 308 uploadConfig(config); 309 310 String markTime = getCurrentLogcatDate(); 311 doAppBreadcrumbReportedStart(6); // value = 6, which is NOT > trigger 312 Thread.sleep(WAIT_AFTER_BREADCRUMB_MS); 313 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 314 if (PERFETTO_TESTS_ENABLED) assertThat(isSystemTracingEnabled()).isFalse(); 315 316 doAppBreadcrumbReportedStart(14); // value = 14 > trigger 317 Thread.sleep(WAIT_AFTER_BREADCRUMB_MS); 318 319 List<EventMetricData> data = getEventMetricDataList(); 320 assertWithMessage("Expected anomaly").that(data).hasSize(1); 321 assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID); 322 323 // Pool a few times to allow for statsd <-> traced <-> traced_probes communication to happen. 324 if (PERFETTO_TESTS_ENABLED) { 325 boolean tracingEnabled = false; 326 for (int i = 0; i < 5; i++) { 327 if (isSystemTracingEnabled()) { 328 tracingEnabled = true; 329 break; 330 } 331 Thread.sleep(1000); 332 } 333 assertThat(tracingEnabled).isTrue(); 334 } 335 } 336 337 // Tests that anomaly detection for gauge works. testGaugeAnomalyDetection()338 public void testGaugeAnomalyDetection() throws Exception { 339 StatsdConfig.Builder config = getBaseConfig(1, 20, 6 /* threshold: value > 6 */) 340 .addGaugeMetric(GaugeMetric.newBuilder() 341 .setId(METRIC_ID) 342 .setWhat(APP_BREADCRUMB_REPORTED_MATCH_START_ID) 343 .setBucket(TimeUnit.CTS) 344 // Get the label field's value into the gauge: 345 .setGaugeFieldsFilter( 346 FieldFilter.newBuilder().setFields(FieldMatcher.newBuilder() 347 .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER) 348 .addChild(FieldMatcher.newBuilder() 349 .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)) 350 ) 351 ) 352 ); 353 uploadConfig(config); 354 355 String markTime = getCurrentLogcatDate(); 356 doAppBreadcrumbReportedStart(6); // gauge = 6, which is NOT > trigger 357 Thread.sleep(Math.max(WAIT_AFTER_BREADCRUMB_MS, 1_100)); // Must be >1s to push next bucket. 358 assertWithMessage("Premature anomaly").that(getEventMetricDataList()).isEmpty(); 359 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isFalse(); 360 361 // We waited for >1s above, so we are now in the next bucket (which is essential). 362 doAppBreadcrumbReportedStart(14); // gauge = 14 > trigger 363 Thread.sleep(WAIT_AFTER_BREADCRUMB_MS); 364 365 List<EventMetricData> data = getEventMetricDataList(); 366 assertWithMessage("Expected anomaly").that(data).hasSize(1); 367 assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID); 368 if (INCIDENTD_TESTS_ENABLED) assertThat(didIncidentdFireSince(markTime)).isTrue(); 369 } 370 371 // Test that anomaly detection for pulled metrics work. testPulledAnomalyDetection()372 public void testPulledAnomalyDetection() throws Exception { 373 final int ATOM_ID = Atom.DEBUG_ELAPSED_CLOCK_FIELD_NUMBER; // A pulled atom 374 final int VALUE_FIELD = 375 DebugElapsedClock.ELAPSED_CLOCK_MILLIS_FIELD_NUMBER; // Something that will be > 0. 376 final int ATOM_MATCHER_ID = 300; 377 378 StatsdConfig.Builder config = getBaseConfig(10, 20, 0 /* threshold: value > 0 */) 379 .addAllowedLogSource("AID_SYSTEM") 380 // Track the ATOM_ID pulled atom 381 .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder() 382 .setId(ATOM_MATCHER_ID) 383 .setSimpleAtomMatcher(StatsdConfigProto.SimpleAtomMatcher.newBuilder() 384 .setAtomId(ATOM_ID))) 385 .addGaugeMetric(GaugeMetric.newBuilder() 386 .setId(METRIC_ID) 387 .setWhat(ATOM_MATCHER_ID) 388 .setBucket(TimeUnit.CTS) 389 .setSamplingType(GaugeMetric.SamplingType.RANDOM_ONE_SAMPLE) 390 // Track the VALUE_FIELD (anomaly detection requires exactly one field here) 391 .setGaugeFieldsFilter( 392 FieldFilter.newBuilder().setFields(FieldMatcher.newBuilder() 393 .setField(ATOM_ID) 394 .addChild(FieldMatcher.newBuilder().setField(VALUE_FIELD)) 395 ) 396 ) 397 ); 398 uploadConfig(config); 399 400 Thread.sleep(6_000); // Wait long enough to ensure AlarmManager signals >= 1 pull 401 402 List<EventMetricData> data = getEventMetricDataList(); 403 assertThat(data.size()).isEqualTo(1); 404 assertThat(data.get(0).getAtom().getAnomalyDetected().getAlertId()).isEqualTo(ALERT_ID); 405 } 406 407 getBaseConfig(int numBuckets, int refractorySecs, long triggerIfSumGt)408 private final StatsdConfig.Builder getBaseConfig(int numBuckets, 409 int refractorySecs, 410 long triggerIfSumGt) throws Exception { 411 return createConfigBuilder() 412 // Items of relevance for detecting the anomaly: 413 .addAtomMatcher( 414 StatsdConfigProto.AtomMatcher.newBuilder() 415 .setId(APP_BREADCRUMB_REPORTED_MATCH_START_ID) 416 .setSimpleAtomMatcher( 417 StatsdConfigProto.SimpleAtomMatcher.newBuilder() 418 .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER) 419 // Event only when the uid is this app's uid. 420 .addFieldValueMatcher(createFvm(AppBreadcrumbReported.UID_FIELD_NUMBER) 421 .setEqInt(getHostUid())) 422 .addFieldValueMatcher( 423 createFvm(AppBreadcrumbReported.STATE_FIELD_NUMBER) 424 .setEqInt(AppBreadcrumbReported.State.START.ordinal())))) 425 .addAtomMatcher( 426 StatsdConfigProto.AtomMatcher.newBuilder() 427 .setId(APP_BREADCRUMB_REPORTED_MATCH_STOP_ID) 428 .setSimpleAtomMatcher( 429 StatsdConfigProto.SimpleAtomMatcher.newBuilder() 430 .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER) 431 // Event only when the uid is this app's uid. 432 .addFieldValueMatcher(createFvm(AppBreadcrumbReported.UID_FIELD_NUMBER) 433 .setEqInt(getHostUid())) 434 .addFieldValueMatcher( 435 createFvm(AppBreadcrumbReported.STATE_FIELD_NUMBER) 436 .setEqInt(AppBreadcrumbReported.State.STOP.ordinal())))) 437 .addAlert(Alert.newBuilder() 438 .setId(ALERT_ID) 439 .setMetricId(METRIC_ID) // The metric itself must yet be added by the test. 440 .setNumBuckets(numBuckets) 441 .setRefractoryPeriodSecs(refractorySecs) 442 .setTriggerIfSumGt(triggerIfSumGt)) 443 .addSubscription( 444 Subscription.newBuilder() 445 .setId(SUBSCRIPTION_ID_INCIDENTD) 446 .setRuleType(Subscription.RuleType.ALERT) 447 .setRuleId(ALERT_ID) 448 .setIncidentdDetails(IncidentdDetails.newBuilder().addSection(INCIDENTD_SECTION))) 449 // We want to trigger anomalies on METRIC_ID, but don't want the actual data. 450 .addNoReportMetric(METRIC_ID) 451 452 // Items of relevance to reporting the anomaly (we do want this data): 453 .addAtomMatcher( 454 StatsdConfigProto.AtomMatcher.newBuilder() 455 .setId(ANOMALY_DETECT_MATCH_ID) 456 .setSimpleAtomMatcher( 457 StatsdConfigProto.SimpleAtomMatcher.newBuilder() 458 .setAtomId(Atom.ANOMALY_DETECTED_FIELD_NUMBER) 459 .addFieldValueMatcher(createFvm(AnomalyDetected.CONFIG_UID_FIELD_NUMBER) 460 .setEqInt(getHostUid())) 461 .addFieldValueMatcher(createFvm(AnomalyDetected.CONFIG_ID_FIELD_NUMBER) 462 .setEqInt(CONFIG_ID)))) 463 .addEventMetric(StatsdConfigProto.EventMetric.newBuilder() 464 .setId(ANOMALY_EVENT_ID) 465 .setWhat(ANOMALY_DETECT_MATCH_ID)); 466 } 467 } 468