1# Copyright 2018, The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Utility functions for metrics.""" 16 17import sys 18import time 19import traceback 20 21from atest.metrics import metrics 22from atest.metrics import metrics_base 23 24 25CONTENT_LICENSES_URL = 'https://source.android.com/setup/start/licenses' 26CONTRIBUTOR_AGREEMENT_URL = { 27 'INTERNAL': 'https://cla.developers.google.com/', 28 'EXTERNAL': 'https://opensource.google.com/docs/cla/', 29} 30PRIVACY_POLICY_URL = 'https://policies.google.com/privacy' 31TERMS_SERVICE_URL = 'https://policies.google.com/terms' 32 33 34def static_var(varname, value): 35 """Decorator to cache static variable.""" 36 37 def fun_var_decorate(func): 38 """Set the static variable in a function.""" 39 setattr(func, varname, value) 40 return func 41 42 return fun_var_decorate 43 44 45@static_var('start_time', []) 46def get_start_time(): 47 """Get start time. 48 49 Return: 50 start_time: Start time in seconds. Return cached start_time if exists, 51 time.time() otherwise. 52 """ 53 if not get_start_time.start_time: 54 get_start_time.start_time = time.time() 55 return get_start_time.start_time 56 57 58def convert_duration(diff_time_sec): 59 """Compute duration from time difference. 60 61 A Duration represents a signed, fixed-length span of time represented 62 as a count of seconds and fractions of seconds at nanosecond 63 resolution. 64 65 Args: 66 diff_time_sec: The time in seconds as a floating point number. 67 68 Returns: 69 A dict of Duration. 70 """ 71 seconds = int(diff_time_sec) 72 nanos = int((diff_time_sec - seconds) * 10**9) 73 return {'seconds': seconds, 'nanos': nanos} 74 75 76# pylint: disable=broad-except 77def handle_exc_and_send_exit_event(exit_code): 78 """handle exceptions and send exit event. 79 80 Args: 81 exit_code: An integer of exit code. 82 """ 83 stacktrace = logs = '' 84 try: 85 exc_type, exc_msg, _ = sys.exc_info() 86 stacktrace = traceback.format_exc() 87 if exc_type: 88 logs = '{etype}: {value}'.format(etype=exc_type.__name__, value=exc_msg) 89 except Exception: 90 pass 91 send_exit_event(exit_code, stacktrace=stacktrace, logs=logs) 92 93 94def send_exit_event(exit_code, stacktrace='', logs=''): 95 """Log exit event and flush all events to clearcut. 96 97 Args: 98 exit_code: An integer of exit code. 99 stacktrace: A string of stacktrace. 100 logs: A string of logs. 101 """ 102 clearcut = metrics.AtestExitEvent( 103 duration=convert_duration(time.time() - get_start_time()), 104 exit_code=exit_code, 105 stacktrace=stacktrace, 106 logs=str(logs), 107 ) 108 # pylint: disable=no-member 109 if clearcut: 110 clearcut.flush_events() 111 112 113def send_start_event( 114 command_line, 115 test_references, 116 cwd, 117 operating_system, 118 source_root, 119 hostname, 120): 121 """Log start event of clearcut. 122 123 Args: 124 command_line: A string of the user input command. 125 test_references: A string of the input tests. 126 cwd: A string of current path. 127 operating_system: A string of user's operating system. 128 source_root: A string of the Android build source. 129 hostname: A string of the host workstation name. 130 """ 131 get_start_time() 132 metrics.AtestStartEvent( 133 command_line=command_line, 134 test_references=test_references, 135 cwd=cwd, 136 os=operating_system, 137 source_root=source_root, 138 hostname=hostname, 139 ) 140 141 142def print_data_collection_notice(colorful=True): 143 """Print the data collection notice.""" 144 # Do not print notice for external users as we are not collecting any external 145 # data. 146 if metrics_base.get_user_type() == metrics_base.EXTERNAL_USER: 147 return 148 149 red = '31m' 150 green = '32m' 151 start = '\033[1;' 152 end = '\033[0m' 153 delimiter = '=' * 18 154 notice = ( 155 'We collect usage statistics (including usernames) in accordance with our ' 156 'Content Licenses (%s), Contributor License Agreement (%s), Privacy ' 157 'Policy (%s) and Terms of Service (%s).' 158 ) % ( 159 CONTENT_LICENSES_URL, 160 CONTRIBUTOR_AGREEMENT_URL['INTERNAL'], 161 PRIVACY_POLICY_URL, 162 TERMS_SERVICE_URL, 163 ) 164 if colorful: 165 print(f'\n{delimiter}\n{start}{red}Notice:{end}') 166 print(f'{start}{green} {notice}{end}\n{delimiter}\n') 167 else: 168 print(f'\n{delimiter}\nNotice:') 169 print(f' {notice}\n{delimiter}\n') 170