blob: 2d034e50f4b5709bee3411e44016e1caa365ab21 [file] [log] [blame]
/*
* Copyright (C) 2017 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.
*/
// Version 1.
// Important: Update the version line above before copy-pasting this file
// from/to Google3 and Android repository.
// This proto needs to be manually synced between Google3 and Android versions.
/*
* Note about semantics of the buckets:
* In this current proto scheme, the buckets are updated only when an event
* occurs. In the case of durations, this means that we update at the end of a
* duration.
*
* For example, suppose we have buckets at every 10 min:
* 0, 10, 20, 30, 40, etc.
* And then suppose a wakelock is first held starting at min 5 and lasts for 21
* mins. Then the buckets for 0-10 and 10-20 don't contain anything and inside
* the bucket for 20-30, we add the value of 21 minutes.
*
* Also note that buckets are only aligned to wall-clock (no custom time-bases).
*/
syntax = "proto2";
package android.os.statsd;
option optimize_for = LITE_RUNTIME;
option java_package = "com.android.internal.os";
option java_outer_classname = "StatsdConfigProto";
// KeyMatcher specifies how to match the key.
message KeyMatcher {
oneof contents {
int32 key = 1; // ID of the key to match.
// Special matcher for package name. This will match either the package name
// or the UID (statsD will map the UID of the source event to a package
// name). Specify the package name to match in eq_string.
bool use_package = 2;
}
}
// FieldMatcher allows us to match specific fields/keys in an event.
message FieldMatcher {
optional KeyMatcher key_matcher = 1;
oneof value_matcher {
// Equality matchers
bool eq_bool = 2;
string eq_string = 3;
int32 eq_int32 = 4;
int64 eq_int64 = 5;
// Numeric comparisons;
int32 lt_int32 = 6;
int32 gt_int32 = 7;
int64 lt_int64 = 8;
int64 gt_int64 = 9;
float lt_float = 10;
float gt_float = 11;
}
}
enum OperationType {
AND = 1;
OR = 2;
NOT = 3; // Must have only a single operand when using NOT operator.
NAND = 4; // NAND and NOR as conveniences to avoid NOT+(AND/OR)-layers.
NOR = 5;
}
enum TrackedAggregateType {
// IS_RUNNING; // whether it is currently running
VALUE_COUNT = 1; // count number of events
VALUE_SUM = 2;
VALUE_MAX = 3;
VALUE_MIN = 4;
DURATION_SUM = 5; // cumulative total time
DURATION_MAX = 6; // longest continuously-on time
DURATION_MIN = 7; // shortest continuously-on time
//DURATION_CURRENT = 6; // current continuously-on time (not bucketed)
}
// Assume the events come in with a tag and an array of (key, value) tuples
// where the key must be an int32 and value can be any type.
message LineMatcher {
// For now, we assume that we don't flatten the tags (ie, one tag corresponds
// to screen-on and screen-off events and key 1 represents ON or OFF).
repeated int32 tag = 1; // Must match at least one of the tags.
message Nested {
optional OperationType operation = 1;
repeated LineMatcher matcher = 2;
}
oneof contents {
FieldMatcher requirement = 2;
Nested nested = 3;
}
}
// Defines when an AggregateCounter or EventMatcher applies.
message Condition {
message Nested {
optional OperationType operation = 1;
repeated Condition nested_conditions = 2; // operands that are themselves
// conditions (recursively)
}
// Leaf node of condition.
message RangeMatcher {
optional LineMatcher start = 1;
optional LineMatcher stop = 2;
optional bool count_nesting = 3
[default = true]; // true if "start start stop" is still
// considered running
// Configure which fields define the slices. These fields must be present in
// both the start and stop lines. Note that this can be a subset of all the
// slices defined in the AggregateCounter.
// For example, if the counter slices on both app name and wake lock name,
// we can define that this range only slices on app name.
repeated KeyMatcher slice = 4;
}
oneof contents {
RangeMatcher range = 1; // Represents a leaf node.
Nested nested = 2; // Represents a non-leaf node.
}
}
// Emits matching events to statsd event buffer.
message EventMatcher {
// Tracks what configuration led to uploading of this event.
optional int32 metric_id = 1;
// LineMatcher for the event to emit.
optional LineMatcher what = 2;
optional Condition condition = 3;
// TODO: Have a clear use-case for this in P or-else drop this for P.
message Filter {
}
optional Filter filter = 4;
}
// Hard-code the possible metrics that we can pull.
// For example, NETSTATS_BY_UID would provide network usage per uid.
// We should treat the results like a batch of individual log events, and we
// should process them one-by-one to re-use our LineMatcher logic.
enum PulledMetricSource {
NETSTATS = 1;
}
message AggregateCounter { // previously called Timer
// Specifies which fields in the message act as dimensions.
// For both pushed and pulled metrics, we assume every record has all the
// dimensions set.
message Slicer {
repeated KeyMatcher keys = 1;
}
optional Slicer slicer = 1;
message ValueSource {
message PushedMetric {
// LineMatcher for the event to apply.
// Slicing (which keys act as dimensions) should not be specified here.
optional LineMatcher what = 1;
// Only needed if one key should be treated as the value.
optional int32 value_key = 2;
}
// The values for pulled metrics are computed and aggregated at the end of
// the condition.
message PulledMetric {
optional bool compute_diff =
1; // If we want the diff (if this
// metric is pulled when condition opens/closes).
optional PulledMetricSource metric = 2;
// We treat the pulled metrics as a batch of log-records that look like
// they came from LogD.
optional LineMatcher what = 3;
optional int32 value_field = 4;
}
oneof value {
PushedMetric pushed_metric = 1;
// Pulled metrics are computed when the duration closes (and are also
// fetched at the open if we need to compute a diff).
// Pulled metrics require a condition being defined.
// These metrics are not pulled at the end of every bucket.
PulledMetric pulled_metric = 2;
// Polled Metrics are pulled at the end of every bucket.
// Since the buckets are only planned to be on wall-clock for Android P,
// condition is NOT supported for polled metrics.
PulledMetric polled_metric = 3;
}
}
optional ValueSource value = 2;
message TrackedAggregate {
// Must be an integer that is uniquely chosen so we can identify the metric
// on server. We will provide a tool on server to help generate this.
optional int32 metric_id = 1;
optional TrackedAggregateType type = 2;
// Alert if the value, when summed over the Counter's number_of_buckets
// most-recent bins, exceeds min_threshold or is below max_threshold. For
// Anomaly Detection.
message Alert {
message IncidentdDetails {
optional string
alert_name = 1; // for humans and incidentd to identify this issue
repeated int32 incidentd_sections = 2; // tells incidentd what to do if
// alert triggers
}
optional IncidentdDetails incidentd_details = 1;
optional int32 number_of_buckets = 2;
// NOTE: that we assume the aggregate is only int.
optional int64 trigger_if_gt = 3; // min threshold
optional int64 trigger_if_lt = 4; // max_threshold;
optional int32 refractory_period_secs = 5; // alarm cannot fire a second
// time until elapsed
}
repeated Alert alerts = 3; // Support diff alert params for same aggregate.
} // end TrackedAggregate
repeated TrackedAggregate tracked_aggregates = 3;
optional Condition condition = 4;
message Bucket {
// TODO: Consider switching to second granularity.
// In practice, this must be chosen from a pre-defined list. So that we have
// flexiblity, we don't hard-code this as an enum today.
optional int64 bucket_size_msec = 1;
optional int32 max_number_of_bits = 2; // Max bits per bucket.
}
optional Bucket bucket = 5;
message MiscellaneousEffect {
optional LineMatcher matcher = 1; // When to trigger the effect
enum Effect {
STOP_ALL = 1; // Needed for stop-all events, where nested start value is
// forced to 0.
}
repeated Effect effects = 2;
} // end MiscellaneousEffect
repeated MiscellaneousEffect misc_effects = 6;
} // end Counter
// Alarm configs not tied to a particular Counter.
message GlobalAlertParameters {
// No alarm can fire after any other alarm fired until this many seconds has
// elapsed.
optional int32 global_refractory_period_seconds = 1;
}
// The config defining all metrics to be captured.
message StatsdConfig {
// Event matchers.
repeated EventMatcher event_matchers = 1;
// Aggregate counters.
repeated AggregateCounter aggregate_counters = 2;
}
/* Sample configurations start here:
----Screen on time----
AggregateCounter <
condition <
range <
start <
tag: SCREEN_ON
requirement <
key_matcher<
key: SCREEN_ON_VALUE
eq_bool: true
stop <
tag: SCREEN_ON
requirement <
key_matcher<
key: SCREEN_ON_VALUE
eq_bool: false
metric_id: # set on server
tracked_aggregates <
DURATION_SUM
(For brevity, omit the bucket options but they can also be set)
----Screen off time----
Should be like aboe but reversing start and stop
----Log the screen change events----
EventMatcher <
metric_id: # set on server
what <
tag: SCREEN_ON
----Number of crashes (across system)----
AggregateCounter <
metric_id: # set on server
tracked_aggregates <
VALUE_COUNT
value <
pushed_metric <
what <
tag: CRASH_TAG
----Network Usage in bytes Per App While in Background----
AggregateCounter <
metric_id: # set on server
slicer <
keys <
use_package_name: true
tracked_aggregates <
VALUE_SUM
value <
pulled_metric <
compute_diff: true
metric: Enum corresponding to network usage in bytes
condition <
range <
sliced: true
start <
tag: APP_FOREGROUND_TRANSITION (assume false means move to background)
requirement <
key_matcher<
key: APP_FOREGROUND_STATE
eq_bool: false
stop <
tag: APP_FOREGROUND_TRANSITION (assume false means move to background)
requirement <
key_matcher<
key: APP_FOREGROUND_STATE
eq_bool: true
----Wakelock Acquire time per app and wakelock
while unplugged and screen off and in background process state----
AggregateCounter <
metric_id: # set on server
slicer <
keys <
use_package_name: true
keys <
key: Key corresponding to wake_lock ID
tracked_aggregates <
DURATION_SUM
condition <
nested <
operation: AND
nested_conditions <
range <
start <
tag: PLUGGED_IN (assume false means uncharged)
requirement <
key_matcher<
key: PLUGGED_IN_STATE
eq_bool: false
stop <
tag: PLUGGED_IN (assume false means uncharged)
requirement <
key_matcher<
key: PLUGGED_IN_STATE
eq_bool: true
nested_conditions <
range <
start <
tag: SCREEN_ON
requirement <
key_matcher<
key: SCREEN_ON_STATE
eq_bool: false
stop <
tag: SCREEN_ON
requirement <
key_matcher<
key: SCREEN_ON_STATE
eq_bool: true
nested_conditions <
range <
start <
tag: PROCESS_CHANGE
requirement <
key_matcher<
key: PROCESS_STATE_VALUE
eq_int32: BACKGROUND_PROCESS
stop <
tag: PROCESS_CHANGE
nested <
operation: NOT
matcher< (This is an example of using the NOT to define stop)
requirement < (Note this requirement should match the start.)
key_matcher<
key: PROCESS_STATE_VALUE
eq_int32: BACKGROUND_PROCESS
slice<
use_package_name: true
----Number of crashes (per app) ----
AggregateCounter <
metric_id: # set on server
slicer <
keys<
use_package_name: true
tracked_aggregates <
VALUE_COUNT
value <
pushed_metric <
what <
tag: CRASH_TAG
---- Number of transitions to background (per app) ----
AggregateCounter <
metric_id: # set on server
slicer <
keys<
use_package_name: true
tracked_aggregates <
VALUE_COUNT
value <
pushed_metric <
what <
tag: APP_FOREGROUND_TRANSITION
requirement<
key: APP_FOREGROUND_TRANSITION_STATE
eq_bool: false
*/