measures.py (3095B)
1 #!/usr/bin/env vpython3 2 3 # Copyright 2024 The Chromium Authors 4 # Use of this source code is governed by a BSD-style license that can be 5 # found in the LICENSE file. 6 """ The module to create and manage measures using in the process. """ 7 8 import json 9 import os 10 import sys 11 12 from google.protobuf import any_pb2 13 from google.protobuf.json_format import MessageToDict 14 15 # Add to sys.path so that this module can be imported by other modules that 16 # have different path setup, e.g. android test runner, and ios test runner. 17 sys.path.append(os.path.abspath(os.path.dirname(__file__))) 18 from average import Average 19 from count import Count 20 from data_points import DataPoints 21 from measure import Measure 22 from metric import Metric 23 from time_consumption import TimeConsumption 24 25 # This is used as the key when being uploaded to ResultDB via result_sink 26 # and shouldn't be changed 27 TEST_SCRIPT_METRICS_KEY = 'test_script_metrics' 28 29 # The file name is used as the key when being loaded into the ResultDB and 30 # shouldn't be changed. 31 TEST_SCRIPT_METRICS_JSONPB_FILENAME = f'{TEST_SCRIPT_METRICS_KEY}.jsonpb' 32 33 _metric = Metric() 34 35 36 def _create_name(*name_pieces: str) -> str: 37 if len(name_pieces) == 0: 38 raise ValueError('Need at least one name piece.') 39 return '/'.join(list(name_pieces)) 40 41 42 def _register(m: Measure) -> Measure: 43 _metric.register(m) 44 return m 45 46 47 def average(*name_pieces: str) -> Average: 48 return _register(Average(_create_name(*name_pieces))) 49 50 51 def count(*name_pieces: str) -> Count: 52 return _register(Count(_create_name(*name_pieces))) 53 54 55 def data_points(*name_pieces: str) -> DataPoints: 56 return _register(DataPoints(_create_name(*name_pieces))) 57 58 59 def time_consumption(*name_pieces: str) -> TimeConsumption: 60 return _register(TimeConsumption(_create_name(*name_pieces))) 61 62 63 def tag(*args: str) -> None: 64 """Adds a tag to the Metric to tag the final results; see Metric for details. 65 """ 66 _metric.tag(*args) 67 68 69 def clear() -> None: 70 """Clears all the registered Measures.""" 71 _metric.clear() 72 73 74 def size() -> int: 75 """Gets the current size of registered Measures.""" 76 return _metric.size() 77 78 def to_dict() -> dict: 79 """Converts all the registered Measures to a dict. 80 81 The records are wrapped in protobuf Any message before exported as dict 82 so that an additional key "@type" is included. 83 """ 84 any_msg = any_pb2.Any() 85 any_msg.Pack(_metric.dump()) 86 return MessageToDict(any_msg, preserving_proto_field_name=True) 87 88 89 def to_json() -> str: 90 """Converts all the registered Measures to a json str.""" 91 return json.dumps(to_dict(), sort_keys=True, indent=2) 92 93 # TODO(crbug.com/343242386): May need to implement a lock and reset logic to 94 # clear in-memory data and lock the instance to block further operations and 95 # avoid accidentally accumulating data which won't be published at all. 96 def dump(dir_path: str) -> None: 97 """Dumps the metric data into test_script_metrics.jsonpb in the |path|.""" 98 os.makedirs(dir_path, exist_ok=True) 99 with open(os.path.join(dir_path, TEST_SCRIPT_METRICS_JSONPB_FILENAME), 100 'w', 101 encoding='utf-8') as wf: 102 wf.write(to_json())