# Copyright 2018, The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Utility functions for metrics. """ import os import platform import sys import time import traceback from atest.metrics import metrics from atest.metrics import metrics_base CONTENT_LICENSES_URL = 'https://source.android.com/setup/start/licenses' CONTRIBUTOR_AGREEMENT_URL = { 'INTERNAL': 'https://cla.developers.google.com/', 'EXTERNAL': 'https://opensource.google.com/docs/cla/' } PRIVACY_POLICY_URL = 'https://policies.google.com/privacy' TERMS_SERVICE_URL = 'https://policies.google.com/terms' def static_var(varname, value): """Decorator to cache static variable.""" def fun_var_decorate(func): """Set the static variable in a function.""" setattr(func, varname, value) return func return fun_var_decorate @static_var("start_time", []) def get_start_time(): """Get start time. Return: start_time: Start time in seconds. Return cached start_time if exists, time.time() otherwise. """ if not get_start_time.start_time: get_start_time.start_time = time.time() return get_start_time.start_time def convert_duration(diff_time_sec): """Compute duration from time difference. A Duration represents a signed, fixed-length span of time represented as a count of seconds and fractions of seconds at nanosecond resolution. Args: diff_time_sec: The time in seconds as a floating point number. Returns: A dict of Duration. """ seconds = int(diff_time_sec) nanos = int((diff_time_sec - seconds)*10**9) return {'seconds': seconds, 'nanos': nanos} # pylint: disable=broad-except def handle_exc_and_send_exit_event(exit_code): """handle exceptions and send exit event. Args: exit_code: An integer of exit code. """ stacktrace = logs = '' try: exc_type, exc_msg, _ = sys.exc_info() stacktrace = traceback.format_exc() if exc_type: logs = '{etype}: {value}'.format(etype=exc_type.__name__, value=exc_msg) except Exception: pass send_exit_event(exit_code, stacktrace=stacktrace, logs=logs) def send_exit_event(exit_code, stacktrace='', logs=''): """Log exit event and flush all events to clearcut. Args: exit_code: An integer of exit code. stacktrace: A string of stacktrace. logs: A string of logs. """ clearcut = metrics.AtestExitEvent( duration=convert_duration(time.time()-get_start_time()), exit_code=exit_code, stacktrace=stacktrace, logs=str(logs)) # pylint: disable=no-member if clearcut: clearcut.flush_events() def send_start_event(tool_name, command_line='', test_references='', cwd=None, operating_system=None): """Log start event of clearcut. Args: tool_name: A string of the asuite product name. command_line: A string of the user input command. test_references: A string of the input tests. cwd: A string of current path. operating_system: A string of user's operating system. """ if not cwd: cwd = os.getcwd() if not operating_system: operating_system = platform.platform() # Without tool_name information, asuite's clearcut client will not send # event to server. metrics_base.MetricsBase.tool_name = tool_name get_start_time() metrics.AtestStartEvent(command_line=command_line, test_references=test_references, cwd=cwd, os=operating_system) def print_data_collection_notice(colorful=True): """Print the data collection notice.""" red = '31m' green = '32m' start = '\033[1;' end = '\033[0m' delimiter = '=' * 18 anonymous = '' user_type = 'INTERNAL' if metrics_base.get_user_type() == metrics_base.EXTERNAL_USER: anonymous = ' anonymous' user_type = 'EXTERNAL' notice = (' We collect%s usage statistics in accordance with our Content ' 'Licenses (%s), Contributor License Agreement (%s), Privacy ' 'Policy (%s) and Terms of Service (%s).' ) % (anonymous, CONTENT_LICENSES_URL, CONTRIBUTOR_AGREEMENT_URL[user_type], PRIVACY_POLICY_URL, TERMS_SERVICE_URL) if colorful: print(f'\n{delimiter}\n{start}{red}Notice:{end}') print(f'{start}{green} {notice}{end}\n{delimiter}\n') else: print(f'\n{delimiter}\nNotice:') print(f' {notice}\n{delimiter}\n')