Translate Android log entries to stats_log proto
Test: tested on local device
Change-Id: If9a779a96d31cefaffb1e4424629c14b08e1fc57
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index f1b3c05..9c2e63e4 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -46,6 +46,7 @@
src/LogReader.cpp \
src/main.cpp \
src/DropboxWriter.cpp \
+ src/parse_util.cpp \
src/StatsLogProcessor.cpp \
src/stats_log.proto \
src/statsd_config.proto \
diff --git a/cmds/statsd/src/DropboxReader.cpp b/cmds/statsd/src/DropboxReader.cpp
index 187f4ad..cda2f43 100644
--- a/cmds/statsd/src/DropboxReader.cpp
+++ b/cmds/statsd/src/DropboxReader.cpp
@@ -15,9 +15,7 @@
*/
#include <android/os/DropBoxManager.h>
#include <android-base/file.h>
-#include <cutils/log.h>
#include <androidfw/ZipUtils.h>
-#include <stdio.h>
#include "DropboxReader.h"
@@ -25,14 +23,14 @@
using android::String16;
using android::binder::Status;
using android::base::unique_fd;
+using android::os::statsd::EventMetricData;
using android::os::DropBoxManager;
-using android::os::statsd::StatsLogEntry;
using android::ZipUtils;
using std::vector;
status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) {
sp<DropBoxManager> dropbox = new DropBoxManager();
- StatsLogList logList;
+ StatsLogReport logReport;
long timestamp = msec;
// instead of while(true), put a hard limit 1000. Dropbox won't have more than 1000 files.
@@ -51,23 +49,23 @@
timestamp = entry.getTimestamp();
if (entry.getFlags() & DropBoxManager::IS_GZIPPED) {
- if (!parseFromGzipFile(fd, logList)) {
+ if (!parseFromGzipFile(fd, logReport)) {
// Failed to parse from the file. Continue to fetch the next entry.
continue;
}
} else {
- if (!parseFromFile(fd, logList)) {
+ if (!parseFromFile(fd, logReport)) {
// Failed to parse from the file. Continue to fetch the next entry.
continue;
}
}
- printLog(out, logList);
+ printLog(out, logReport);
}
return android::OK;
}
-bool DropboxReader::parseFromGzipFile(const unique_fd& fd, StatsLogList& list) {
+bool DropboxReader::parseFromGzipFile(const unique_fd& fd, StatsLogReport& logReport) {
FILE *file = fdopen(fd, "r");
bool result = false;
bool scanResult;
@@ -80,7 +78,7 @@
if (scanResult && method == kCompressDeflated) {
vector<uint8_t> buf(uncompressedLen);
if (ZipUtils::inflateToBuffer(file, &buf[0], uncompressedLen, compressedLen)) {
- if (list.ParseFromArray(&buf[0], uncompressedLen)) {
+ if (logReport.ParseFromArray(&buf[0], uncompressedLen)) {
result = true;
}
}
@@ -92,29 +90,30 @@
}
// parse a non zipped file.
-bool DropboxReader::parseFromFile(const unique_fd& fd, StatsLogList& list) {
+bool DropboxReader::parseFromFile(const unique_fd& fd, StatsLogReport& logReport) {
string content;
if (!android::base::ReadFdToString(fd, &content)) {
ALOGE("Failed to read file");
return false;
}
- if (!list.ParseFromString(content)) {
+ if (!logReport.ParseFromString(content)) {
ALOGE("failed to parse log entry from data");
return false;
}
return true;
}
-void DropboxReader::printLog(FILE* out, const StatsLogList& list) {
- for (int i = 0; i < list.stats_log_entry_size(); i++) {
- const StatsLogEntry entry = list.stats_log_entry(i);
- // TODO: print pretty
- fprintf(out, "time_msec=%lld, type=%d, aggregate_type=%d, uid=%d, pid=%d ",
- entry.start_report_millis(), entry.type(), entry.aggregate_type(),
- entry.uid(), entry.pid());
- for (int j = 0; j < entry.pairs_size(); j++) {
- fprintf(out, "msg=%s ", entry.pairs(j).value_str().c_str());
+void DropboxReader::printLog(FILE* out, const StatsLogReport& logReport) {
+ fprintf(out, "start_time_msec=%lld, end_time_msec=%lld, ",
+ logReport.start_report_millis(), logReport.end_report_millis());
+ for (int i = 0; i < logReport.event_metrics().data_size(); i++) {
+ EventMetricData eventMetricData = logReport.event_metrics().data(i);
+ for (int j = 0; j < eventMetricData.key_value_pair_size(); j++) {
+ fprintf(out, "key=%d, ", eventMetricData.key_value_pair(j).key());
+ fprintf(out, "value_str=%s ", eventMetricData.key_value_pair(j).value_str().c_str());
+ fprintf(out, "value_int=%lld ", eventMetricData.key_value_pair(j).value_int());
+ fprintf(out, "value_float=%f ", eventMetricData.key_value_pair(j).value_float());
}
- fprintf(out, "\n");
}
+ fprintf(out, "\n");
}
diff --git a/cmds/statsd/src/DropboxReader.h b/cmds/statsd/src/DropboxReader.h
index a62ffde..f7d5a82 100644
--- a/cmds/statsd/src/DropboxReader.h
+++ b/cmds/statsd/src/DropboxReader.h
@@ -23,7 +23,7 @@
#include <stdio.h>
using android::base::unique_fd;
-using android::os::statsd::StatsLogList;
+using android::os::statsd::StatsLogReport;
using android::status_t;
using std::string;
@@ -33,13 +33,13 @@
static status_t readStatsLogs(FILE* out, const string& tag, long msec);
private:
- static bool parseFromFile(const unique_fd& fd, StatsLogList& list);
- static bool parseFromGzipFile(const unique_fd& fd, StatsLogList& list);
- static void printLog(FILE* out, const StatsLogList& list);
+ static bool parseFromFile(const unique_fd& fd, StatsLogReport& logReport);
+ static bool parseFromGzipFile(const unique_fd& fd, StatsLogReport& logReport);
+ static void printLog(FILE* out, const StatsLogReport& logReport);
enum {
kCompressStored = 0, // no compression
kCompressDeflated = 8, // standard deflate
};
};
-#endif //DROPBOX_READER_H
\ No newline at end of file
+#endif //DROPBOX_READER_H
diff --git a/cmds/statsd/src/DropboxWriter.cpp b/cmds/statsd/src/DropboxWriter.cpp
index a251056..01a9eac 100644
--- a/cmds/statsd/src/DropboxWriter.cpp
+++ b/cmds/statsd/src/DropboxWriter.cpp
@@ -15,7 +15,6 @@
*/
#include <android/os/DropBoxManager.h>
-#include <cutils/log.h>
#include "DropboxWriter.h"
@@ -26,36 +25,35 @@
using std::vector;
DropboxWriter::DropboxWriter(const string& tag)
- : mTag(tag), mLogList(), mBufferSize(0) {
+ : mTag(tag), mLogReport(), mBufferSize(0) {
}
-void DropboxWriter::addEntry(const StatsLogEntry& entry) {
- flushIfNecessary(entry);
- StatsLogEntry* newEntry = mLogList.add_stats_log_entry();
- newEntry->CopyFrom(entry);
- mBufferSize += entry.ByteSize();
+void DropboxWriter::addStatsLogReport(const StatsLogReport& log) {
+ mLogReport = log;
+ flushIfNecessary(log);
+ mBufferSize += log.ByteSize();
}
-void DropboxWriter::flushIfNecessary(const StatsLogEntry& entry) {
- // The serialized size of the StatsLogList is approximately the sum of the serialized size of
- // every StatsLogEntry inside it.
- if (entry.ByteSize() + mBufferSize > kMaxSerializedBytes) {
- flush();
- }
+void DropboxWriter::flushIfNecessary(const StatsLogReport& log) {
+ // TODO: Decide to flush depending on the serialized size of the StatsLogReport.
+ // if (entry.ByteSize() + mBufferSize > kMaxSerializedBytes) {
+ // flush();
+ // }
+ flush();
}
void DropboxWriter::flush() {
// now we get an exact byte size of the output
- const int numBytes = mLogList.ByteSize();
+ const int numBytes = mLogReport.ByteSize();
vector<uint8_t> buffer(numBytes);
sp<DropBoxManager> dropbox = new DropBoxManager();
- mLogList.SerializeToArray(&buffer[0], numBytes);
+ mLogReport.SerializeToArray(&buffer[0], numBytes);
Status status = dropbox->addData(String16(mTag.c_str()), &buffer[0],
numBytes, 0 /* no flag */);
if (!status.isOk()) {
ALOGE("failed to write to dropbox");
//TODO: What to do if flush fails??
}
- mLogList.Clear();
+ mLogReport.Clear();
mBufferSize = 0;
}
diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/DropboxWriter.h
index 176ac8b..31b3f27 100644
--- a/cmds/statsd/src/DropboxWriter.h
+++ b/cmds/statsd/src/DropboxWriter.h
@@ -20,8 +20,7 @@
#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
using std::string;
-using android::os::statsd::StatsLogEntry;
-using android::os::statsd::StatsLogList;
+using android::os::statsd::StatsLogReport;
class DropboxWriter {
public:
@@ -30,7 +29,7 @@
*/
DropboxWriter(const string& tag);
- void addEntry(const StatsLogEntry& entry);
+ void addStatsLogReport(const StatsLogReport& log);
/* Request a flush to dropbox. */
void flush();
@@ -46,11 +45,11 @@
const string mTag;
- /* StatsLogList is a wrapper for storing a list of StatsLogEntry */
- StatsLogList mLogList;
+ /* Data that was captured for a single metric over a given interval of time. */
+ StatsLogReport mLogReport;
/* Current *serialized* size of the logs kept in memory.
- To save computation, we will not calculate the size of the StatsLogList every time when a new
+ To save computation, we will not calculate the size of the StatsLogReport every time when a new
entry is added, which would recursively call ByteSize() on every log entry. Instead, we keep
the sum of all individual stats log entry sizes. The size of a proto is approximately the sum
of the size of all member protos.
@@ -59,7 +58,7 @@
/* Check if the buffer size exceeds the max buffer size when the new entry is added, and flush
the logs to dropbox if true. */
- void flushIfNecessary(const StatsLogEntry& entry);
+ void flushIfNecessary(const StatsLogReport& log);
};
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 5f5e216..c2fffd8 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -16,14 +16,13 @@
#include <StatsLogProcessor.h>
-#include <log/event_tag_map.h>
-#include <log/logprint.h>
+#include <log/log_event_list.h>
#include <utils/Errors.h>
-#include <cutils/log.h>
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
+#include <parse_util.h>
using namespace android;
-using android::os::statsd::StatsLogEntry;
+using android::os::statsd::EventMetricData;
+using android::os::statsd::StatsLogReport;
StatsLogProcessor::StatsLogProcessor() : m_dropbox_writer("all-logs")
{
@@ -57,12 +56,12 @@
// dump all statsd logs to dropbox for now.
// TODO: Add filtering, aggregation, etc.
if (err == NO_ERROR) {
- StatsLogEntry logEntry;
- logEntry.set_uid(entry.uid);
- logEntry.set_pid(entry.pid);
- logEntry.set_start_report_millis(entry.tv_sec / 1000 + entry.tv_nsec / 1000 / 1000);
- logEntry.add_pairs()->set_value_str(entry.message, entry.messageLen);
- m_dropbox_writer.addEntry(logEntry);
+ StatsLogReport logReport;
+ logReport.set_start_report_millis(entry.tv_sec / 1000 + entry.tv_nsec / 1000 / 1000);
+ EventMetricData *eventMetricData = logReport.mutable_event_metrics()->add_data();
+ *eventMetricData = parse(msg);
+
+ m_dropbox_writer.addStatsLogReport(logReport);
}
}
@@ -71,4 +70,4 @@
{
m_configs[config_source] = config;
ALOGD("Updated configuration for source %i", config_source);
-}
\ No newline at end of file
+}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index d2daecd..5df8424 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -16,12 +16,8 @@
#ifndef STATS_LOG_PROCESSOR_H
#define STATS_LOG_PROCESSOR_H
-#include "LogReader.h"
-#include "DropboxWriter.h"
+#include "parse_util.h"
-#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
-#include <log/logprint.h>
-#include <stdio.h>
#include <unordered_map>
using android::os::statsd::StatsdConfig;
diff --git a/cmds/statsd/src/parse_util.cpp b/cmds/statsd/src/parse_util.cpp
new file mode 100644
index 0000000..9caeacf
--- /dev/null
+++ b/cmds/statsd/src/parse_util.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include <parse_util.h>
+#include <log/log_event_list.h>
+
+using android::os::statsd::EventMetricData;
+using android::os::statsd::KeyId;
+using android::os::statsd::KeyId_IsValid;
+using android::os::statsd::KeyValuePair;
+using android::os::statsd::TagId;
+using android::os::statsd::TagId_IsValid;
+
+EventMetricData parse(log_msg msg)
+{
+ // dump all statsd logs to dropbox for now.
+ // TODO: Add filtering, aggregation, etc.
+ EventMetricData eventMetricData;
+ android_log_context context = create_android_log_parser(const_cast<log_msg*>(&msg)->msg()
+ + sizeof(uint32_t),
+ const_cast<log_msg*>(&msg)->len()
+ - sizeof(uint32_t));
+ android_log_list_element elem;
+
+ if (context) {
+ memset(&elem, 0, sizeof(elem));
+ size_t index = 0;
+ int32_t key = -1;
+ int32_t tag = -1;
+
+ do {
+ elem = android_log_read_next(context);
+ switch ((int)elem.type) {
+ case EVENT_TYPE_INT:
+ if (index == 0) {
+ tag = elem.data.int32;
+ if (TagId_IsValid(tag)) {
+ eventMetricData.set_tag(static_cast<TagId>(tag));
+ } else {
+ break;
+ }
+ } else if (index % 2 == 1) {
+ key = elem.data.int32;
+ } else if (KeyId_IsValid(key)) {
+ int32_t val = elem.data.int32;
+ KeyValuePair *keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(static_cast<KeyId>(key));
+ keyValuePair->set_value_int(val);
+ } else {
+ }
+ index++;
+ break;
+ case EVENT_TYPE_FLOAT:
+ if (index % 2 == 0 && KeyId_IsValid(key)) {
+ float val = elem.data.float32;
+ KeyValuePair *keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(static_cast<KeyId>(key));
+ keyValuePair->set_value_float(val);
+ }
+ index++;
+ break;
+ case EVENT_TYPE_STRING:
+ if (index % 2 == 0 && KeyId_IsValid(key)) {
+ char* val = elem.data.string;
+ KeyValuePair *keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(static_cast<KeyId>(key));
+ keyValuePair->set_value_str(val);
+ }
+ index++;
+ break;
+ case EVENT_TYPE_LONG:
+ if (index % 2 == 0 && KeyId_IsValid(key)) {
+ int64_t val = elem.data.int64;
+ KeyValuePair *keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(static_cast<KeyId>(key));
+ keyValuePair->set_value_int(val);
+ }
+ index++;
+ break;
+ case EVENT_TYPE_LIST:
+ break;
+ case EVENT_TYPE_LIST_STOP:
+ break;
+ case EVENT_TYPE_UNKNOWN:
+ break;
+ default:
+ elem.complete = true;
+ break;
+ }
+
+ if (elem.complete) {
+ break;
+ }
+ } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
+
+ android_log_destroy(&context);
+ }
+
+ return eventMetricData;
+}
diff --git a/cmds/statsd/src/parse_util.h b/cmds/statsd/src/parse_util.h
new file mode 100644
index 0000000..8750f82
--- /dev/null
+++ b/cmds/statsd/src/parse_util.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+#ifndef PARSE_UTIL_H
+#define PARSE_UTIL_H
+
+#include "LogReader.h"
+#include "DropboxWriter.h"
+
+#include <log/logprint.h>
+
+using android::os::statsd::EventMetricData;
+
+EventMetricData parse(const log_msg msg);
+
+#endif // PARSE_UTIL_H
diff --git a/cmds/statsd/src/stats_constants.proto b/cmds/statsd/src/stats_constants.proto
index 1787ae3..3f8bd1c 100644
--- a/cmds/statsd/src/stats_constants.proto
+++ b/cmds/statsd/src/stats_constants.proto
@@ -22,10 +22,17 @@
option java_package = "com.android.internal.logging";
option java_outer_classname = "StatsConstantsProto";
-message StatsConstants {
- // Event type.
- enum Type {
- WAKELOCK = 1;
- SCREEN= 2;
- }
+enum TagId {
+ WAKELOCK = 1;
+ SCREEN = 1003;
+}
+
+enum KeyId {
+ STATE = 1;
+ ANOTHER_STATE = 2;
+ EVENT_TIMESTAMP = 1001;
+ PACKAGE_NAME = 1002;
+ PACKAGE_VERSION = 1003;
+ PACKAGE_VERSION_STRING = 1004;
+ ATTRIBUTION_CHAIN = 1005;
}
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index ec92023..2c66ded 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -25,53 +25,53 @@
import "frameworks/base/cmds/statsd/src/statsd_config.proto";
import "frameworks/base/cmds/statsd/src/stats_constants.proto";
-// StatsLogEntry is a generic proto holding a single metrics data.
-message StatsLogEntry {
- // Type of stats.
- optional android.os.statsd.StatsConstants.Type type = 1;
+message KeyValuePair {
+ optional KeyId key = 1;
- // Aggregation type of the data.
- optional android.os.statsd.TrackedAggregateType aggregate_type = 2;
-
- // Start timestamp of the interval. Timestamp for event-type data will have
- // equal value for start_report_millis and end_report_millis.
- optional int64 start_report_millis = 3;
-
- // End timestamp of the interval.
- optional int64 end_report_millis = 4;
-
- // Package information for application-level data.
- optional string package_name = 5;
- optional int32 package_version = 6;
- optional string package_version_string = 7;
-
- // UID associated with the data.
- optional int32 uid = 8;
-
- // PID associated with the data.
- optional int32 pid = 9;
-
- // Payload contains key value pairs of the data from statsd.
- message KeyValuePair {
- // Integer representation of data type.
- optional int32 key = 1;
-
- oneof value {
- string value_str = 2;
- int64 value_int = 3;
- bool value_bool = 4;
- }
+ oneof value {
+ string value_str = 2;
+ int64 value_int = 3;
+ bool value_bool = 4;
+ float value_float = 5;
}
- repeated KeyValuePair pairs = 10;
-
- // Next tag: 11
}
-// Data captured for a given metric during a given period of time.
-message StatsLogList {
- // Unique ID for this metric.
+message EventMetricData {
+ optional TagId tag = 1;
+
+ repeated KeyValuePair key_value_pair = 2;
+}
+
+message CountBucketInfo {
+ optional int64 start_bucket_millis = 1;
+
+ optional int64 end_bucket_millis = 2;
+
+ optional int64 count = 3;
+}
+
+message CountMetricData {
+ repeated KeyValuePair dimension = 1;
+
+ repeated CountBucketInfo bucket_info = 2;
+}
+
+message StatsLogReport {
optional int32 metric_id = 1;
- // List of stats log entry.
- repeated StatsLogEntry stats_log_entry = 2;
+ optional int64 start_report_millis = 2;
+
+ optional int64 end_report_millis = 3;
+
+ message EventMetricDataWrapper {
+ repeated EventMetricData data = 1;
+ }
+ message CountMetricDataWrapper {
+ repeated CountMetricData data = 1;
+ }
+
+ oneof data {
+ EventMetricDataWrapper event_metrics = 4;
+ CountMetricDataWrapper count_metrics = 5;
+ }
}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 2d034e5..c6119df 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -1,40 +1,3 @@
-/*
- * 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;
@@ -43,30 +6,21 @@
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.
+import "frameworks/base/cmds/statsd/src/stats_constants.proto";
- // 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;
- }
+message KeyMatcher {
+ optional KeyId key = 1;
+ optional bool as_package_name = 2 [ default = false ];
}
-// FieldMatcher allows us to match specific fields/keys in an event.
-message FieldMatcher {
+message KeyValueMatcher {
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;
@@ -76,374 +30,90 @@
}
}
-enum OperationType {
+enum LogicalOperation {
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.
+ NOT = 3;
+ NAND = 4;
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)
+message SimpleLogEntryMatcher {
+ repeated TagId tag = 1;
+
+ repeated KeyValueMatcher key_value_matcher = 2;
}
-// 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 LogEntryMatcher {
+ optional string name = 1;
- message Nested {
- optional OperationType operation = 1;
- repeated LineMatcher matcher = 2;
+ message Combination {
+ optional LogicalOperation operation = 1;
+ repeated LogEntryMatcher matcher = 2;
}
oneof contents {
- FieldMatcher requirement = 2;
- Nested nested = 3;
+ SimpleLogEntryMatcher simple_log_entry_matcher = 2;
+ Combination combination = 3;
}
}
-// Defines when an AggregateCounter or EventMatcher applies.
+message SimpleCondition {
+ optional string start = 1;
+
+ optional string stop = 2;
+
+ optional bool count_nesting = 3 [default = true];
+
+ optional string stop_all = 4;
+}
+
message Condition {
- message Nested {
- optional OperationType operation = 1;
- repeated Condition nested_conditions = 2; // operands that are themselves
- // conditions (recursively)
- }
+ optional string name = 1;
- // 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
+ message Combination {
+ optional LogicalOperation operation = 1;
- // 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;
+ repeated string condition = 2;
}
oneof contents {
- RangeMatcher range = 1; // Represents a leaf node.
- Nested nested = 2; // Represents a non-leaf node.
+ SimpleCondition simple_condition = 2;
+ Combination combination = 3;
}
}
-// 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;
+message Bucket {
+ optional int64 bucket_size_millis = 1;
}
-// 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 EventMetric {
+ optional int64 metric_id = 1;
+
+ optional string what = 2;
+
+ optional string condition = 3;
}
-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 CountMetric {
+ optional int64 metric_id = 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;
+ optional string what = 2;
- // Only needed if one key should be treated as the value.
- optional int32 value_key = 2;
- }
+ optional string condition = 3;
- // 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;
+ repeated KeyMatcher dimension = 4;
- // 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;
+ optional int64 config_id = 1;
- // Aggregate counters.
- repeated AggregateCounter aggregate_counters = 2;
+ repeated EventMetric event_metric = 2;
+
+ repeated CountMetric count_metric = 3;
+
+ repeated LogEntryMatcher log_entry_matcher = 4;
+
+ repeated Condition condition = 5;
}
-
-/* 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
-
-*/