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""" 16Utility functions for metrics. 17""" 18 19import os 20import platform 21import sys 22import time 23import traceback 24 25from . import metrics 26from . import metrics_base 27 28 29def static_var(varname, value): 30 """Decorator to cache static variable.""" 31 def fun_var_decorate(func): 32 """Set the static variable in a function.""" 33 setattr(func, varname, value) 34 return func 35 return fun_var_decorate 36 37 38@static_var("start_time", []) 39def get_start_time(): 40 """Get start time. 41 42 Return: 43 start_time: Start time in seconds. Return cached start_time if exists, 44 time.time() otherwise. 45 """ 46 if not get_start_time.start_time: 47 get_start_time.start_time = time.time() 48 return get_start_time.start_time 49 50 51def convert_duration(diff_time_sec): 52 """Compute duration from time difference. 53 54 A Duration represents a signed, fixed-length span of time represented 55 as a count of seconds and fractions of seconds at nanosecond 56 resolution. 57 58 Args: 59 dur_time_sec: The time in seconds as a floating point number. 60 61 Returns: 62 A dict of Duration. 63 """ 64 seconds = int(diff_time_sec) 65 nanos = int((diff_time_sec - seconds)*10**9) 66 return {'seconds': seconds, 'nanos': nanos} 67 68 69# pylint: disable=broad-except 70def handle_exc_and_send_exit_event(exit_code): 71 """handle exceptions and send exit event. 72 73 Args: 74 exit_code: An integer of exit code. 75 """ 76 stacktrace = logs = '' 77 try: 78 exc_type, exc_msg, _ = sys.exc_info() 79 stacktrace = traceback.format_exc() 80 if exc_type: 81 logs = '{etype}: {value}'.format(etype=exc_type.__name__, 82 value=exc_msg) 83 except Exception: 84 pass 85 send_exit_event(exit_code, stacktrace=stacktrace, logs=logs) 86 87 88def send_exit_event(exit_code, stacktrace='', logs=''): 89 """Log exit event and flush all events to clearcut. 90 91 Args: 92 exit_code: An integer of exit code. 93 stacktrace: A string of stacktrace. 94 logs: A string of logs. 95 """ 96 clearcut = metrics.AtestExitEvent( 97 duration=convert_duration(time.time()-get_start_time()), 98 exit_code=exit_code, 99 stacktrace=stacktrace, 100 logs=logs) 101 # pylint: disable=no-member 102 if clearcut: 103 clearcut.flush_events() 104 105 106def send_start_event(tool_name, command_line='', test_references='', 107 cwd=None, operating_system=None): 108 """Log start event of clearcut. 109 110 Args: 111 tool_name: A string of the asuite product name. 112 command_line: A string of the user input command. 113 test_references: A string of the input tests. 114 cwd: A string of current path. 115 operating_system: A string of user's operating system. 116 """ 117 if not cwd: 118 cwd = os.getcwd() 119 if not operating_system: 120 operating_system = platform.platform() 121 # Without tool_name information, asuite's clearcut client will not send 122 # event to server. 123 metrics_base.MetricsBase.tool_name = tool_name 124 get_start_time() 125 metrics.AtestStartEvent(command_line=command_line, 126 test_references=test_references, 127 cwd=cwd, 128 os=operating_system) 129