# 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 . import metrics from . import metrics_base 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: dur_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=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)