Commit 1e59a247 authored by Edward Lesmes's avatar Edward Lesmes Committed by LUCI CQ

metrics: Report bot metrics if DEPOT_TOOLS_REPORT_BUILD is set

If the DEPOT_TOOLS_REPORT_BUILD envvar is set, Depot Tools will
report information about the builder running the command
(e.g. buildbucket project, bucket, builder and build id).

It will also authenticate to the metrics server, and ignore any
requests not made by ChOps service accounts.

Change-Id: I078a4c2170b4226086c42f289fa449bdebc87179
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2861213
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
Reviewed-by: 's avatarJosip Sokcevic <sokcevic@google.com>
parent cc7ab346
...@@ -117,12 +117,16 @@ class _Config(object): ...@@ -117,12 +117,16 @@ class _Config(object):
@property @property
def should_collect_metrics(self): def should_collect_metrics(self):
# Don't collect the metrics unless the user is a googler, the user has opted # DEPOT_TOOLS_REPORT_BUILD is set on bots to report metrics.
# in, or the countdown has expired. if os.getenv(metrics_utils.DEPOT_TOOLS_REPORT_BUILD):
return True
# Don't report metrics if user is not a Googler.
if not self.is_googler: if not self.is_googler:
return False return False
# Don't report metrics if user has opted out.
if self.opted_in is False: if self.opted_in is False:
return False return False
# Don't report metrics if countdown hasn't reached 0.
if self.opted_in is None and self.countdown > 0: if self.opted_in is None and self.countdown > 0:
return False return False
return True return True
...@@ -227,6 +231,10 @@ class MetricsCollector(object): ...@@ -227,6 +231,10 @@ class MetricsCollector(object):
if git_version: if git_version:
self.add('git_version', git_version) self.add('git_version', git_version)
bot_metrics = metrics_utils.get_bot_metrics()
if bot_metrics:
self.add('bot_metrics', bot_metrics)
self._upload_metrics_data() self._upload_metrics_data()
if exception: if exception:
gclient_utils.reraise(exception[0], exception[1], exception[2]) gclient_utils.reraise(exception[0], exception[1], exception[2])
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
from __future__ import print_function from __future__ import print_function
import re import re
import os
import scm import scm
import subprocess2 import subprocess2
import sys import sys
...@@ -19,10 +20,13 @@ except ImportError: # For Py3 compatibility ...@@ -19,10 +20,13 @@ except ImportError: # For Py3 compatibility
# Current version of metrics recording. # Current version of metrics recording.
# When we add new metrics, the version number will be increased, we display the # When we add new metrics, the version number will be increased, we display the
# user what has changed, and ask the user to agree again. # user what has changed, and ask the user to agree again.
CURRENT_VERSION = 1 CURRENT_VERSION = 2
APP_URL = 'https://cit-cli-metrics.appspot.com' APP_URL = 'https://cit-cli-metrics.appspot.com'
DEPOT_TOOLS_REPORT_BUILD = 'DEPOT_TOOLS_REPORT_BUILD'
def get_notice_countdown_header(countdown): def get_notice_countdown_header(countdown):
if countdown == 0: if countdown == 0:
yield ' METRICS COLLECTION IS TAKING PLACE' yield ' METRICS COLLECTION IS TAKING PLACE'
...@@ -43,15 +47,28 @@ def get_notice_footer(): ...@@ -43,15 +47,28 @@ def get_notice_footer():
def get_change_notice(version): def get_change_notice(version):
if version == 0: if version == 0:
pass # No changes for version 0 return [] # No changes for version 0
elif version == 1: elif version == 1:
yield 'We want to collect the Git version.' return [
yield 'We want to collect information about the HTTP' 'We want to collect the Git version.',
yield 'requests that depot_tools makes, and the git and' 'We want to collect information about the HTTP',
yield 'cipd commands it executes.' 'requests that depot_tools makes, and the git and',
yield '' 'cipd commands it executes.',
yield 'We only collect known strings to make sure we' '',
yield 'don\'t record PII.' 'We only collect known strings to make sure we',
'don\'t record PII.',
]
elif version == 2:
return [
'We will start collecting metrics from bots.',
'There are no changes for developers.',
'If the DEPOT_TOOLS_REPORT_BUILD environment variable is set,',
'we will report information about the current build',
'(e.g. buildbucket project, bucket, builder and build id),',
'and authenticate to the metrics collection server.',
'This information will only be recorded for requests',
'authenticated as bot service accounts.',
]
KNOWN_PROJECT_URLS = { KNOWN_PROJECT_URLS = {
...@@ -174,6 +191,22 @@ def get_git_version(): ...@@ -174,6 +191,22 @@ def get_git_version():
return '%s.%s.%s' % match.groups() return '%s.%s.%s' % match.groups()
def get_bot_metrics():
build = os.getenv(DEPOT_TOOLS_REPORT_BUILD)
if not build or build.count('/') != 3:
return None
project, bucket, builder, build = build.split('/')
return {
'build_id': int(build),
'builder': {
'project': project,
'bucket': bucket,
'builder': builder,
},
}
def return_code_from_exception(exception): def return_code_from_exception(exception):
"""Returns the exit code that would result of raising the exception.""" """Returns the exit code that would result of raising the exception."""
if exception is None: if exception is None:
...@@ -289,5 +322,5 @@ def print_version_change(config_version): ...@@ -289,5 +322,5 @@ def print_version_change(config_version):
lines = list(get_notice_version_change_header()) lines = list(get_notice_version_change_header())
for version in range(config_version + 1, CURRENT_VERSION + 1): for version in range(config_version + 1, CURRENT_VERSION + 1):
lines.append('') lines.append('')
lines += list(get_change_notice(version)) lines += get_change_notice(version)
print_boxed_text(sys.stderr.write, 49, lines) print_boxed_text(sys.stderr.write, 49, lines)
#!/usr/bin/env python #!/usr/bin/env vpython3
# Copyright (c) 2018 The Chromium Authors. All rights reserved. # Copyright (c) 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import os
import sys import sys
import urllib.error
import urllib.request
from third_party.six.moves import urllib import auth
from third_party.six.moves import input # pylint: disable=redefined-builtin
import metrics_utils import metrics_utils
def main(): def main():
metrics = input() metrics = input()
try: try:
urllib.request.urlopen( headers = {}
metrics_utils.APP_URL + '/upload', metrics.encode('utf-8')) if 'bot_metrics' in metrics:
token = auth.Authenticator().get_access_token().token
headers = {'Authorization': 'Bearer ' + token}
urllib.request.urlopen(urllib.request.Request(
url=metrics_utils.APP_URL + '/upload',
data=metrics.encode('utf-8'),
headers=headers))
except (urllib.error.HTTPError, urllib.error.URLError): except (urllib.error.HTTPError, urllib.error.URLError):
pass pass
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment