metrics: create framework for metric event gathering
Here I introduce some scaffolding for recording metrics events. This
data is aggregated and plumbed back through the Build API interface's
response protobufs. Currently only InstallPackagesResponse is hooked up.
The plan is to begin exploring this data via Analysis service, then
pivot as necessary towards finding ways to analyze, monitor and alert on
it.
BUG=chromium:989179
TEST=manual testing with api/contrib/call_scripts/sysroot__install_packages
Change-Id: I69fcd43112ffb5c6ab34eb584ec28ccd655914ce
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1727269
Tested-by: Will Bradley <wbbradley@chromium.org>
Reviewed-by: Alex Klein <saklein@chromium.org>
Commit-Queue: Will Bradley <wbbradley@chromium.org>
diff --git a/api/metrics_unittest.py b/api/metrics_unittest.py
new file mode 100644
index 0000000..f900f89
--- /dev/null
+++ b/api/metrics_unittest.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for the api/metrics library."""
+
+from __future__ import print_function
+
+import mock
+
+from chromite.api import metrics
+from chromite.api.gen.chromite.api import build_api_test_pb2
+from chromite.lib import cros_test_lib
+from chromite.utils.metrics import (MetricEvent, OP_NAMED_EVENT, OP_START_TIMER,
+ OP_STOP_TIMER)
+
+
+class MetricsTest(cros_test_lib.TestCase):
+ """Test Metrics deserialization functionality at the API layer."""
+
+ def testDeserializeTimer(self):
+ """Test timer math and deserialization into proto objects."""
+ response = build_api_test_pb2.TestResultMessage()
+ mock_events = [
+ MetricEvent(600, 'a.b', OP_START_TIMER, key='100'),
+ MetricEvent(1000, 'a.b', OP_STOP_TIMER, key='100'),
+ ]
+ with mock.patch('chromite.api.metrics.metrics.read_metrics_events',
+ return_value=mock_events):
+ metrics.deserialize_metrics_log(response.events)
+ self.assertEqual(len(response.events), 1)
+ self.assertEqual(response.events[0].name, 'a.b')
+ self.assertEqual(response.events[0].timestamp_milliseconds, 1000)
+ self.assertEqual(response.events[0].duration_milliseconds, 1000-600)
+
+ def testDeserializeNamedEvent(self):
+ """Test deserialization of a named event.
+
+ This test also includes a prefix to test for proper prepending.
+ """
+ response = build_api_test_pb2.TestResultMessage()
+ mock_events = [
+ MetricEvent(1000, 'a.named_event', OP_NAMED_EVENT, key=None),
+ ]
+ with mock.patch('chromite.api.metrics.metrics.read_metrics_events',
+ return_value=mock_events):
+ metrics.deserialize_metrics_log(response.events, prefix='prefix')
+ self.assertEqual(len(response.events), 1)
+ self.assertEqual(response.events[0].name, 'prefix.a.named_event')
+ self.assertEqual(response.events[0].timestamp_milliseconds, 1000)
+ self.assertFalse(response.events[0].duration_milliseconds)