1#!/usr/bin/env python3 2# 3# Copyright 2016 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import shutil 18 19from acts.metrics.core import ProtoMetric 20from acts.metrics.logger import MetricLogger 21 22 23class BlackboxMappedMetricLogger(MetricLogger): 24 """A MetricLogger for logging and publishing Blackbox metrics from a dict. 25 The dict maps the metric name to the metric value. 26 27 The logger will publish an ActsBlackboxMetricResult message, containing 28 data intended to be uploaded to Blackbox. The message itself contains only 29 minimal information specific to the metric, with the intention being that 30 all other metadata is extracted from the test_run_summary.json. 31 32 This logger will extract an attribute from the test class as the metric 33 result. The metric key will be either the context's identifier or a custom 34 value assigned to this class. 35 36 Attributes: 37 proto_module: The proto module for ActsBlackboxMetricResult. 38 metric_key: The metric key to use. If unset, the logger will use the 39 context's identifier. 40 _metric_map: the map of metric_name -> metric_value to publish 41 to blackbox. If the metric value is set to None, the 42 metric will not be reported. 43 """ 44 45 PROTO_FILE = 'protos/acts_blackbox.proto' 46 47 def __init__(self, metric_key=None, event=None, compiler_out=None): 48 """Initializes a logger for Blackbox metrics. 49 50 Args: 51 metric_key: The metric key to use. If unset, the logger will use 52 the context's identifier. 53 event: The event triggering the creation of this logger. 54 compiler_out: The directory to store the compiled proto module. 55 """ 56 super().__init__(event=event) 57 self.proto_module = self._compile_proto(self.PROTO_FILE, 58 compiler_out=compiler_out) 59 self.metric_key = metric_key 60 self._metric_map = {} 61 62 def _get_metric_key(self, metric_name): 63 """Gets the metric key to use. 64 65 If the metric_key is explicitly set, returns that value. Otherwise, 66 extracts an identifier from the context. 67 68 Args: 69 metric_name: The name of the metric to report. 70 """ 71 if self.metric_key: 72 key = self.metric_key 73 else: 74 key = self._get_blackbox_identifier() 75 key = '%s.%s' % (key, metric_name) 76 return key 77 78 def set_metric_data(self, metric_map): 79 """Sets the map of metrics to be uploaded to Blackbox. Note that 80 this will overwrite all existing added by this function or add_metric. 81 82 Args: 83 metric_map: the map of metric_name -> metric_value to publish 84 to blackbox. If the metric value is set to None, the 85 metric will not be reported. 86 """ 87 self._metric_map = metric_map 88 89 def add_metric(self, metric_name, metric_value): 90 """Adds a metric value to be published later. 91 92 Note that if the metric name has already been added, the metric value 93 will be overwritten. 94 95 Args: 96 metric_name: the name of the metric. 97 metric_value: the value of the metric. 98 """ 99 self._metric_map[metric_name] = metric_value 100 101 def _get_blackbox_identifier(self): 102 """Returns the testcase identifier, as expected by Blackbox.""" 103 # b/119787228: Blackbox requires function names to look like Java 104 # functions. 105 identifier = self.context.identifier 106 parts = identifier.rsplit('.', 1) 107 return '#'.join(parts) 108 109 def end(self, _): 110 """Creates and publishes a ProtoMetric with blackbox data. 111 112 Builds a list of ActsBlackboxMetricResult messages from the set 113 metric data, and sends them to the publisher. 114 """ 115 metrics = [] 116 for metric_name, metric_value in self._metric_map.items(): 117 if metric_value is None: 118 continue 119 result = self.proto_module.ActsBlackboxMetricResult() 120 result.test_identifier = self._get_blackbox_identifier() 121 result.metric_key = self._get_metric_key(metric_name) 122 result.metric_value = metric_value 123 124 metrics.append( 125 ProtoMetric(name='blackbox_%s' % metric_name, data=result)) 126 127 return self.publisher.publish(metrics) 128 129 130class BlackboxMetricLogger(BlackboxMappedMetricLogger): 131 """A MetricLogger for logging and publishing individual Blackbox metrics. 132 133 For additional information on reporting to Blackbox, see 134 BlackboxMappedMetricLogger. 135 136 Attributes: 137 proto_module: The proto module for ActsBlackboxMetricResult. 138 metric_name: The name of the metric, used to determine output filename. 139 metric_key: The metric key to use. If unset, the logger will use the 140 context's identifier. 141 metric_value: The metric value. 142 """ 143 144 def __init__(self, metric_name, metric_key=None, event=None, 145 compiler_out=None): 146 """Initializes a logger for Blackbox metrics. 147 148 Args: 149 metric_name: The name of the metric. 150 metric_key: The metric key to use. If unset, the logger will use 151 the context's identifier. 152 event: The event triggering the creation of this logger. 153 compiler_out: The directory to store the compiled proto module 154 """ 155 super().__init__(metric_key=metric_key, event=event, 156 compiler_out=compiler_out) 157 if not metric_name: 158 raise ValueError("metric_name must be supplied.") 159 self.metric_name = metric_name 160 self.metric_value = None 161 162 @property 163 def metric_value(self): 164 return self._metric_map[self.metric_name] 165 166 @metric_value.setter 167 def metric_value(self, value): 168 self.add_metric(self.metric_name, value) 169