blob: 7cff5881079df3b049d3cdd993309ae55e70f201 [file] [log] [blame]
Edward Lemur32e3d1e2018-07-12 00:54:05 +00001#!/usr/bin/env python
2# Copyright (c) 2018 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Edward Lemurc87d45b2018-07-26 17:43:11 +00006from __future__ import print_function
7
Edward Lemur03d6d112018-10-23 15:17:36 +00008import re
Edward Lemur32e3d1e2018-07-12 00:54:05 +00009import scm
10import subprocess2
11import sys
Edward Lemur03d6d112018-10-23 15:17:36 +000012import urlparse
Edward Lemur32e3d1e2018-07-12 00:54:05 +000013
14from third_party import colorama
15
16
Edward Lemur48836262018-10-18 02:08:06 +000017# Current version of metrics recording.
18# When we add new metrics, the version number will be increased, we display the
19# user what has changed, and ask the user to agree again.
20CURRENT_VERSION = 0
21
Edward Lemur5ba1e9c2018-07-23 18:19:02 +000022APP_URL = 'https://cit-cli-metrics.appspot.com'
23
Edward Lemur48836262018-10-18 02:08:06 +000024EMPTY_LINE = (
25 '* *'
26)
Edward Lemur32e3d1e2018-07-12 00:54:05 +000027NOTICE_COUNTDOWN_HEADER = (
28 '*****************************************************\n'
29 '* METRICS COLLECTION WILL START IN %2d EXECUTIONS *'
30)
31NOTICE_COLLECTION_HEADER = (
32 '*****************************************************\n'
33 '* METRICS COLLECTION IS TAKING PLACE *'
34)
Edward Lemur48836262018-10-18 02:08:06 +000035NOTICE_VERSION_CHANGE_HEADER = (
36 '*****************************************************\n'
37 '* WE ARE COLLECTING ADDITIONAL METRICS *'
38)
Edward Lemur32e3d1e2018-07-12 00:54:05 +000039NOTICE_FOOTER = (
Edward Lemur32e3d1e2018-07-12 00:54:05 +000040 '* For more information, and for how to disable this *\n'
41 '* message, please see metrics.README.md in your *\n'
42 '* depot_tools checkout. *\n'
43 '*****************************************************\n'
44)
45
Edward Lemur48836262018-10-18 02:08:06 +000046CHANGE_NOTICE = {
47 # No changes for version 0
48 0: '',
49}
50
51
Edward Lemur40764b02018-07-20 18:50:29 +000052KNOWN_PROJECT_URLS = {
53 'https://chrome-internal.googlesource.com/chrome/ios_internal',
54 'https://chrome-internal.googlesource.com/infra/infra_internal',
55 'https://chromium.googlesource.com/breakpad/breakpad',
56 'https://chromium.googlesource.com/chromium/src',
57 'https://chromium.googlesource.com/chromium/tools/depot_tools',
58 'https://chromium.googlesource.com/crashpad/crashpad',
59 'https://chromium.googlesource.com/external/gyp',
60 'https://chromium.googlesource.com/external/naclports',
61 'https://chromium.googlesource.com/infra/goma/client',
62 'https://chromium.googlesource.com/infra/infra',
63 'https://chromium.googlesource.com/native_client/',
64 'https://chromium.googlesource.com/syzygy',
65 'https://chromium.googlesource.com/v8/v8',
66 'https://dart.googlesource.com/sdk',
67 'https://pdfium.googlesource.com/pdfium',
68 'https://skia.googlesource.com/buildbot',
69 'https://skia.googlesource.com/skia',
70 'https://webrtc.googlesource.com/src',
71}
72
Edward Lemur03d6d112018-10-23 15:17:36 +000073KNOWN_HTTP_HOSTS = {
74 'chrome-internal-review.googlesource.com',
75 'chromium-review.googlesource.com',
76 'dart-review.googlesource.com',
77 'eu1-mirror-chromium-review.googlesource.com',
78 'pdfium-review.googlesource.com',
79 'skia-review.googlesource.com',
80 'us1-mirror-chromium-review.googlesource.com',
81 'us2-mirror-chromium-review.googlesource.com',
82 'us3-mirror-chromium-review.googlesource.com',
83 'webrtc-review.googlesource.com',
84}
85
86KNOWN_HTTP_METHODS = {
87 'DELETE',
88 'GET',
89 'PATCH',
90 'POST',
91 'PUT',
92}
93
94KNOWN_HTTP_PATHS = {
95 'accounts':
96 re.compile(r'(/a)?/accounts/.*'),
97 'changes':
98 re.compile(r'(/a)?/changes/([^/]+)?$'),
99 'changes/abandon':
100 re.compile(r'(/a)?/changes/.*/abandon'),
101 'changes/comments':
102 re.compile(r'(/a)?/changes/.*/comments'),
103 'changes/detail':
104 re.compile(r'(/a)?/changes/.*/detail'),
105 'changes/edit':
106 re.compile(r'(/a)?/changes/.*/edit'),
107 'changes/message':
108 re.compile(r'(/a)?/changes/.*/message'),
109 'changes/restore':
110 re.compile(r'(/a)?/changes/.*/restore'),
111 'changes/reviewers':
112 re.compile(r'(/a)?/changes/.*/reviewers/.*'),
113 'changes/revisions/commit':
114 re.compile(r'(/a)?/changes/.*/revisions/.*/commit'),
115 'changes/revisions/review':
116 re.compile(r'(/a)?/changes/.*/revisions/.*/review'),
117 'changes/submit':
118 re.compile(r'(/a)?/changes/.*/submit'),
119 'projects/branches':
120 re.compile(r'(/a)?/projects/.*/branches/.*'),
121}
122
123KNOWN_HTTP_ARGS = {
124 'ALL_REVISIONS',
125 'CURRENT_COMMIT',
126 'CURRENT_REVISION',
127 'DETAILED_ACCOUNTS',
128 'LABELS',
129}
130
Edward Lemur32e3d1e2018-07-12 00:54:05 +0000131
132def get_python_version():
133 """Return the python version in the major.minor.micro format."""
134 return '{v.major}.{v.minor}.{v.micro}'.format(v=sys.version_info)
135
136
137def return_code_from_exception(exception):
138 """Returns the exit code that would result of raising the exception."""
139 if exception is None:
140 return 0
141 if isinstance(exception[1], SystemExit):
142 return exception[1].code
143 return 1
144
145
146def seconds_to_weeks(duration):
147 """Transform a |duration| from seconds to weeks approximately.
148
149 Drops the lowest 19 bits of the integer representation, which ammounts to
150 about 6 days.
151 """
152 return int(duration) >> 19
153
154
Edward Lemur03d6d112018-10-23 15:17:36 +0000155def extract_http_metrics(request_uri, method, status, response_time):
156 """Extract metrics from the request URI.
157
158 Extracts the host, path, and arguments from the request URI, and returns them
159 along with the method, status and response time.
160
161 The host, method, path and arguments must be in the KNOWN_HTTP_* constants
162 defined above.
163
164 Arguments are the values of the o= url parameter. In Gerrit, additional fields
165 can be obtained by adding o parameters, each option requires more database
166 lookups and slows down the query response time to the client, so we make an
167 effort to collect them.
168
169 The regex defined in KNOWN_HTTP_PATH_RES are checked against the path, and
170 those that match will be returned.
171 """
172 http_metrics = {
173 'status': status,
174 'response_time': response_time,
175 }
176
177 if method in KNOWN_HTTP_METHODS:
178 http_metrics['method'] = method
179
180 parsed_url = urlparse.urlparse(request_uri)
181
182 if parsed_url.netloc in KNOWN_HTTP_HOSTS:
183 http_metrics['host'] = parsed_url.netloc
184
185 for name, path_re in KNOWN_HTTP_PATHS.iteritems():
186 if path_re.match(parsed_url.path):
187 http_metrics['path'] = name
188 break
189
190 parsed_query = urlparse.parse_qs(parsed_url.query)
191
192 # Collect o-parameters from the request.
193 args = [
194 arg for arg in parsed_query.get('o', [])
195 if arg in KNOWN_HTTP_ARGS
196 ]
197 if args:
198 http_metrics['arguments'] = args
199
200 return http_metrics
201
202
Edward Lemur32e3d1e2018-07-12 00:54:05 +0000203def get_repo_timestamp(path_to_repo):
204 """Get an approximate timestamp for the upstream of |path_to_repo|.
205
206 Returns the top two bits of the timestamp of the HEAD for the upstream of the
207 branch path_to_repo is checked out at.
208 """
209 # Get the upstream for the current branch. If we're not in a branch, fallback
210 # to HEAD.
211 try:
212 upstream = scm.GIT.GetUpstreamBranch(path_to_repo)
213 except subprocess2.CalledProcessError:
214 upstream = 'HEAD'
215
216 # Get the timestamp of the HEAD for the upstream of the current branch.
217 p = subprocess2.Popen(
218 ['git', '-C', path_to_repo, 'log', '-n1', upstream, '--format=%at'],
219 stdout=subprocess2.PIPE, stderr=subprocess2.PIPE)
220 stdout, _ = p.communicate()
221
222 # If there was an error, give up.
223 if p.returncode != 0:
224 return None
225
226 # Get the age of the checkout in weeks.
227 return seconds_to_weeks(stdout.strip())
228
229
230def print_notice(countdown):
231 """Print a notice to let the user know the status of metrics collection."""
232 colorama.init()
Edward Lemur48836262018-10-18 02:08:06 +0000233 print(colorama.Fore.RED + '\033[1m', file=sys.stderr, end='')
Edward Lemur32e3d1e2018-07-12 00:54:05 +0000234 if countdown:
Edward Lemurc87d45b2018-07-26 17:43:11 +0000235 print(NOTICE_COUNTDOWN_HEADER % countdown, file=sys.stderr)
Edward Lemur32e3d1e2018-07-12 00:54:05 +0000236 else:
Edward Lemurc87d45b2018-07-26 17:43:11 +0000237 print(NOTICE_COLLECTION_HEADER, file=sys.stderr)
Edward Lemur48836262018-10-18 02:08:06 +0000238 print(EMPTY_LINE, file=sys.stderr)
Edward Lemurc87d45b2018-07-26 17:43:11 +0000239 print(NOTICE_FOOTER + colorama.Style.RESET_ALL, file=sys.stderr)
Edward Lemur48836262018-10-18 02:08:06 +0000240
241
242def print_version_change(config_version):
243 """Print a notice to let the user know we are collecting more metrics."""
244 colorama.init()
245 print(colorama.Fore.RED + '\033[1m', file=sys.stderr, end='')
246 print(NOTICE_VERSION_CHANGE_HEADER, file=sys.stderr)
247 print(EMPTY_LINE, file=sys.stderr)
248 for version in range(config_version + 1, CURRENT_VERSION + 1):
249 print(CHANGE_NOTICE[version], file=sys.stderr)
250 print(EMPTY_LINE, file=sys.stderr)