Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/framework/monitoring.py b/framework/monitoring.py
new file mode 100644
index 0000000..6ddeeb9
--- /dev/null
+++ b/framework/monitoring.py
@@ -0,0 +1,109 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+"""Monitoring ts_mon custom to monorail."""
+
+from infra_libs import ts_mon
+from framework import framework_helpers
+
+
+def GetCommonFields(status, name, is_robot=False):
+  # type: (int, str, bool=False) -> Dict[str, Union[int, str, bool]]
+  return {
+      'status': status,
+      'name': name,
+      'is_robot': is_robot,
+  }
+
+
+API_REQUESTS_COUNT = ts_mon.CounterMetric(
+    'monorail/api_requests',
+    'Number of requests to Monorail APIs',
+    [ts_mon.StringField('client_id'),
+     ts_mon.StringField('client_email'),
+     ts_mon.StringField('version')])
+
+def IncrementAPIRequestsCount(version, client_id, client_email=None):
+  # type: (str, str, Optional[str]) -> None
+  """Increment the request count in ts_mon."""
+  if not client_email:
+    client_email = 'anonymous'
+  elif not framework_helpers.IsServiceAccount(client_email):
+    # Avoid value explosion and protect PII info
+    client_email = 'user@email.com'
+
+  fields = {
+      'client_id': client_id,
+      'client_email': client_email,
+      'version': version
+  }
+  API_REQUESTS_COUNT.increment_by(1, fields)
+
+
+# 90% of durations are in the range 11-1873ms.  Growth factor 10^0.06 puts that
+# range into 37 buckets.  Max finite bucket value is 12 minutes.
+DURATION_BUCKETER = ts_mon.GeometricBucketer(10**0.06)
+
+# 90% of sizes are in the range 0.17-217014 bytes.  Growth factor 10^0.1 puts
+# that range into 54 buckets.  Max finite bucket value is 6.3GB.
+SIZE_BUCKETER = ts_mon.GeometricBucketer(10**0.1)
+
+# TODO(https://crbug.com/monorail/9281): Differentiate internal/external calls.
+SERVER_DURATIONS = ts_mon.CumulativeDistributionMetric(
+    'monorail/server_durations',
+    'Time elapsed between receiving a request and sending a'
+    ' response (including parsing) in milliseconds.', [
+        ts_mon.IntegerField('status'),
+        ts_mon.StringField('name'),
+        ts_mon.BooleanField('is_robot'),
+    ],
+    bucketer=DURATION_BUCKETER)
+
+
+def AddServerDurations(elapsed_ms, fields):
+  # type: (int, Dict[str, Union[int, bool]]) -> None
+  SERVER_DURATIONS.add(elapsed_ms, fields=fields)
+
+
+SERVER_RESPONSE_STATUS = ts_mon.CounterMetric(
+    'monorail/server_response_status',
+    'Number of responses sent by HTTP status code.', [
+        ts_mon.IntegerField('status'),
+        ts_mon.StringField('name'),
+        ts_mon.BooleanField('is_robot'),
+    ])
+
+
+def IncrementServerResponseStatusCount(fields):
+  # type: (Dict[str, Union[int, bool]]) -> None
+  SERVER_RESPONSE_STATUS.increment(fields=fields)
+
+
+SERVER_REQUEST_BYTES = ts_mon.CumulativeDistributionMetric(
+    'monorail/server_request_bytes',
+    'Bytes received per http request (body only).', [
+        ts_mon.IntegerField('status'),
+        ts_mon.StringField('name'),
+        ts_mon.BooleanField('is_robot'),
+    ],
+    bucketer=SIZE_BUCKETER)
+
+
+def AddServerRequesteBytes(request_length, fields):
+  # type: (int, Dict[str, Union[int, bool]]) -> None
+  SERVER_REQUEST_BYTES.add(request_length, fields=fields)
+
+
+SERVER_RESPONSE_BYTES = ts_mon.CumulativeDistributionMetric(
+    'monorail/server_response_bytes',
+    'Bytes sent per http request (content only).', [
+        ts_mon.IntegerField('status'),
+        ts_mon.StringField('name'),
+        ts_mon.BooleanField('is_robot'),
+    ],
+    bucketer=SIZE_BUCKETER)
+
+
+def AddServerResponseBytes(response_length, fields):
+  SERVER_RESPONSE_BYTES.add(response_length, fields=fields)