diff --git a/docs/spirent.rst b/docs/spirent.rst index 54a935a..3ca6a20 100644 --- a/docs/spirent.rst +++ b/docs/spirent.rst @@ -683,6 +683,27 @@ an Spirent traffic generator device: | | current configuration. | | | Arguments: | | | None | + |----------------------------------------------------------------------------------| + | save_result_database | Save database file for all results data to | + | | expected folder. | + | | Arguments: | + | | * [M] file_name - file name without file | + | | extention to save result database | + | | file. | + | | * [O] file_path - file path to save result | + | | database file. | + |----------------------------------------------------------------------------------| + | save_statistics_snapshot_csv | Save statistics view 'GENIE' snapshot as a CSV | + | | Arguments: | + | | * [M] view_name - name of statistic view to| + | | take CSV snapshot of. Can be only | + | | 'GENIE'. | + | | * [O] csv_file_name - file Name for saving | + | | snapshot file. | + | | Default: result_statistics.csv | + | | * [O] csv_save_path - file path to save | + | | the CSV snapshot file as. | + | | Default: ./ | +==================================================================================+ The methods listed above can be executed directly on an Spirent traffic generator diff --git a/src/genie/trafficgen/spirent/implementation.py b/src/genie/trafficgen/spirent/implementation.py index 4c3caaa..ef720ef 100644 --- a/src/genie/trafficgen/spirent/implementation.py +++ b/src/genie/trafficgen/spirent/implementation.py @@ -5,6 +5,7 @@ ''' # Python +import csv import re import os import time @@ -93,7 +94,6 @@ def __init__(self, *args, **kwargs): self.golden_profile = PrettyTable() self.drv_result = None self.drv = None - self.stream_dataset = None # Init class variables self._is_connected = False @@ -431,6 +431,24 @@ def create_genie_statistics_view(self, view_create_interval=30, view_create_iter else: self.create_genie_dynamic_view() + @BaseConnection.locked + @isconnected + def get_traffic_counter_mode(self): + resultview_mode = None + try: + if self._stc_version >= "5.51": + result = self.stc.perform("GetObjectsCommand", ClassName="ResultOptions", propertyList="ResultViewMode") + property_dict = json.loads(result.get('PropertyValues')).values() + for item in property_dict: + resultview_mode = item.get("ResultViewMode") + else: + resultoption = self.stc.get("project1", "children-ResultOptions") + resultview_mode= self.stc.get(resultoption, "ResultViewMode") + return resultview_mode + + except Exception as e: + raise GenieTgnError("Unable to get result view mode on device '{}'".\ + format(self.device.name)) from e @BaseConnection.locked @isconnected @@ -445,6 +463,16 @@ def check_traffic_loss(self, traffic_streams=None, max_outage=120, '''Check for traffic loss on a traffic stream configured on traffic generator device''' log.info(banner("Check for traffic loss on a traffic stream")) + drop_count_supported_mode_list = ["BASIC", "FORWARDING", "LATENCY_JITTER", "LATENCY_JITTER_RFC5481"] + + try: + resultview_mode = self.get_traffic_counter_mode() + + assert resultview_mode in drop_count_supported_mode_list, \ + "Current counter mode '{}' does not support drop frame count.".format(resultview_mode) + except AssertionError as e: + raise GenieTgnError("Fail to check traffic loss") from e + traffic_stream_names = self.get_traffic_stream_names() log.debug(f'Traffic stream names {traffic_stream_names}') seen = set() @@ -536,7 +564,6 @@ def check_traffic_loss(self, traffic_streams=None, max_outage=120, log.error("* Traffic outage of '{c}' seconds is *NOT* within " "expected maximum outage threshold of '{g}' seconds".\ format(c=current_outage, g=verify_max_outage)) - print("outage:", current_outage, verify_max_outage, outage_check) # 2- Verify current loss % is less than tolerance threshold log.info("2. Verify current loss % is less than tolerance " @@ -554,7 +581,6 @@ def check_traffic_loss(self, traffic_streams=None, max_outage=120, log.error("* Current traffic loss of {l}% is *NOT* within" " maximum expected loss tolerance of {g}%".\ format(l=current_loss_percentage, g=verify_loss_tolerance)) - print("loss_percentage:", current_loss_percentage, verify_loss_tolerance, loss_check) ''' # 3- Verify difference between Tx Rate & Rx Rate is less than tolerance threshold log.info("3. Verify difference between Tx Rate & Rx Rate is less " @@ -815,7 +841,8 @@ def create_genie_dynamic_view(self): select_properties = ['StreamBlock.Name', 'Port.Name', 'StreamBlock.TxFrameCount', 'StreamBlock.RxSigFrameCount', 'StreamBlock.DroppedFrameCount','StreamBlock.TxFrameRate', - 'StreamBlock.RxSigFrameRate', 'StreamBlock.DroppedFramePercent'] + 'StreamBlock.RxSigFrameRate', 'StreamBlock.DroppedFramePercent', + 'StreamBlock.ActualRxPortName'] lst_ports = [] try: ports = self.stc.get('Project1', 'children-port') @@ -827,43 +854,15 @@ def create_genie_dynamic_view(self): raise GenieTgnError("No ports found on device '{}'".format(self.device.name)) from e try: - streamblockrdsA = self.stc.perform('ResultsSubscribeCommand', - Parent='project1', - ConfigType="Streamblock", - ResultType="TxStreamBlockResults", - RecordsPerPage=256) - - stream_dataset = streamblockrdsA['ReturnedResultDataSet'] - self.stc.create("ResultQuery", under=stream_dataset, - ResultRootList='project1', - ConfigClassId="StreamBlock", - ResultClassId="RxStreamBlockResults") - - # subscribe to rxstreamsummaryresults - rx_stream_summary_results = self.stc.perform('ResultsSubscribeCommand', - Parent='project1', - ConfigType='Streamblock', - ResultType='RxStreamSummaryResults', - RecordsPerPage=256) - - # subscribe to TxStreamResults - tx_stream_results = self.stc.perform('ResultsSubscribeCommand', - Parent='project1', - ConfigType='Streamblock', - ResultType='TxStreamResults', - RecordsPerPage='256') - self.drv = self.stc.create('DynamicResultView', under='project1', name=GENIE_VIEW_NAME) self.drv_result = self.stc.create('PresentationResultQuery', under=self.drv, name=GENIE_VIEW_NAME) log.info("Create Dynamic view with DRV:{}, DRV Result:{}".format(self.drv, self.drv_result)) self.stc.config(self.drv_result, SelectProperties=select_properties, FromObjects=lst_ports, LimitOffset=0, LimitSize=4000) + #self.stc.config(self.drv_result, SelectProperties=select_properties, FromObjects="project1", LimitOffset=0, LimitSize=4000) self.stc.perform('SubscribeDynamicResultViewCommand', DynamicResultView=self.drv) self.stc.apply() - self.stc.perform("RefreshResultView", ResultDataSet=stream_dataset) - self.stc.perform("UpdateDynamicResultViewCommand", DynamicResultView=self.drv) - except Exception as e: log.error(e) raise GenieTgnError("Unable to Create Genie Statistics View on device '{}'".format(self.device.name)) from e @@ -898,8 +897,12 @@ def create_drv_traffic_streams_table(self): if self.drv == None or self.drv_result == None: self.create_genie_statistics_view() + result_view_data_list = [] try: - #self.stc.perform("RefreshResultView", ResultDataSet=self.stream_dataset) + # recover subscribe + if self.stc.get(self.drv, "ResultState") == "NONE": + self.stc.perform("SubscribeDynamicResultViewCommand", DynamicResultView=self.drv) + self.stc.perform("UpdateDynamicResultViewCommand", DynamicResultView=self.drv) except Exception as e: log.error(e) @@ -910,7 +913,6 @@ def create_drv_traffic_streams_table(self): "Frames Delta","Tx Frame Rate", "Rx Frame Rate", "Loss %", "Outage (seconds)"] - result_view_data_list = [] try: #properties = stc.get(self.drv_result, 'SelectProperties') result_view_data_list = self.stc.get(self.drv_result, 'children-ResultViewData').split() @@ -920,24 +922,6 @@ def create_drv_traffic_streams_table(self): raise GenieTgnError("No result data on device '{}'".format(self.device.name)) from e streams_info = {} - try: - if self._stc_version >= "5.51": - result = self.stc.perform("GetObjectsCommand", ClassName="StreamBlock", PropertyList="Name parent.name children-rxstreamblockresults") - my_dict = json.loads(result['PropertyValues']) - else: - result = self.stc.perform("GetObjectsCommand", ClassName="StreamBlock") - streams_list = result.get("ObjectList").split() - my_dict = {} - for stream in streams_list: - my_dict[stream] = self.stc.get(stream, "Name&parent.name&children-rxstreamblockresults") - - for key in my_dict: - rxport = self.stc.get(my_dict[key]['children-rxstreamblockresults'].split()[0]+'?RxPort') - rxport = "Unknown" if rxport=="" else rxport - streams_info[my_dict[key]['Name']] = rxport.split()[0] - except Exception as e: - log.error(e) - raise GenieTgnError("Unable to Get RX port information on device '{}'".format(self.device.name)) from e try: for result_view_data in result_view_data_list: @@ -945,7 +929,7 @@ def create_drv_traffic_streams_table(self): result_data = self.stc.get(result_view_data, 'ResultData') raw_data = split_string(result_data) - if len(raw_data) != 10: + if len(raw_data) != 11: log.warning("Skip invalid data {}".format(raw_data)) continue @@ -953,7 +937,7 @@ def create_drv_traffic_streams_table(self): stream_name = raw_data[0] - data_list.append(raw_data[1].split()[0]+'-'+streams_info[stream_name]) + data_list.append(raw_data[1].split()[0]+'-'+raw_data[-1].split()[0]) data_list.append(stream_name) #Calculate outage @@ -962,12 +946,18 @@ def create_drv_traffic_streams_table(self): outage = round(float(raw_data[4])/float(raw_data[6]), 3) except ZeroDivisionError: outage = 0.0 + # delete last column + del raw_data[-1] + raw_data.append(str(outage)) data_list += raw_data[2:] traffic_table.add_row(data_list) + # undo subscribe for dynamicresultview and txstreamblockresults + self.stc.perform("UnsubscribeDynamicResultViewCommand", DynamicResultView = self.drv) + except Exception as e: log.error(e) raise GenieTgnError("Unable to Get Genie Statistics on device '{}'".format(self.device.name)) from e @@ -1015,6 +1005,7 @@ def create_tciq_traffic_streams_table(self): raise GenieTgnError("Incorrect Data from TestCenter IQ on device '{}'".format(self.device.name)) for row in all_rows: + row = row[1:-1] # get port pair value row_item = [row[1].split()[0] + "-" + row[2].split()[0]] # get traffic name for traffic item column @@ -1022,14 +1013,17 @@ def create_tciq_traffic_streams_table(self): # get Tx Frames and Rx Frames row_item+= row[3:5] # calcuate frames delta - frames_delta = int(row[3]) - int(row[4]) + #frames_delta = int(row[3]) - int(row[4]) + # use drop count as frame delta + frames_delta = 0 if row[-1] is None else row[-1] row_item.append(frames_delta) # get tx/rx frames rate row_item+= row[5:7] # get tx frame rate tx_frame_rate = row[5] # get frame loss percent - row_item.append(round(float(row[7]),2)) + frame_loss_percent = 0 if row[7] is None else row[7] + row_item.append(round(float(frame_loss_percent),2)) try: outage_seconds = round(float(frames_delta)/float(tx_frame_rate), 3) except ZeroDivisionError: @@ -1117,7 +1111,7 @@ def start_traffic_stream(self, traffic_stream, check_stream=True, wait_time=15, # verify tx rate > 0 log.info("Verify tx rate > 0 for traffic stream '{}'".format(traffic_stream)) - tx_rate = self.get_traffic_statistics_column(traffic_stream, column_field='tx_frame_rate') + tx_rate = self.subscribe_specific_streamblock(stream_handle, 'FrameRate') log.info("tx_rate for traffic stream '{}' is {}(fps).".format(traffic_stream, tx_rate)) @@ -1127,6 +1121,29 @@ def start_traffic_stream(self, traffic_stream, check_stream=True, wait_time=15, log.error("Traffic stream '{}' is started but no frames is send.".format(traffic_stream)) raise GenieTgnError("Traffic stream '{}' is started but no frames is send.".format(traffic_stream)) + @BaseConnection.locked + @isconnected + def subscribe_specific_streamblock(self, streamblock_handle, field): + log.info("Get streamblock tx rate") + try: + resultdataset = self.stc.perform("ResultsSubscribeCommand", ResultType="TxStreamBlockResults", \ + ConfigType="Streamblock", ResultParent=streamblock_handle, parent="project1") + + rs_ds = resultdataset.get('ReturnedDataSet') + + txstreamblockresults = self.stc.get(rs_ds, "resultchild-Targets") + + field_value = self.stc.get(txstreamblockresults, field) + # unsubscribe + self.stc.perform("ResultDataSetUnsubscribeCommand", ResultDataSet=rs_ds) + + return field_value + + except Exception as e: + log.error(e) + raise GenieTgnError("Fail to get '{}' for this traffic".format(field)) + + @BaseConnection.locked @isconnected def stop_traffic_stream(self, traffic_stream, wait_time=15): @@ -1158,7 +1175,7 @@ def stop_traffic_stream(self, traffic_stream, wait_time=15): # verify tx rate = 0 log.info("Verify tx rate = 0 for traffic stream '{}'".format(traffic_stream)) - tx_rate = self.get_traffic_statistics_column(traffic_stream, column_field='tx_frame_rate') + tx_rate = self.subscribe_specific_streamblock(stream_handle, 'FrameRate') if int(tx_rate) == 0: log.info("Traffic stream '{}' has been stopped and rate is equal 0.".format(traffic_stream, tx_rate)) @@ -1166,46 +1183,6 @@ def stop_traffic_stream(self, traffic_stream, wait_time=15): log.error("Traffic stream '{}' is not stopped and rate is {}(fps)".format(traffic_stream, tx_rate)) raise GenieTgnError("Traffic stream '{}' is not stopped and rate is {}(fps)".format(traffic_stream, tx_rate)) - - @BaseConnection.locked - @isconnected - def get_traffic_statistics_column(self, traffic_stream, column_field): - ''' get specific column value from result view''' - ''' column supported: port_pair, stream_block_name, tx_frame_count, rx_frame_count, tx_frame_rate, rx_frame_rate, frame_loss_percent ''' - - # get all data from iq - traffic_table = self.create_traffic_streams_table() - # get all rows - rows = None - if traffic_table: - rows = traffic_table.rows - - if not rows: - log.error("No data results.") - raise GenieTgnError("Unable to get data results.") - - log.info("The data results for all traffic streams:{}".format(rows)) - - target_row = None - # get the exact data for traffic_stream - for row in rows: - if row[1].strip() == traffic_stream: - target_row = row - break - value_dict = {'port_pair':0, 'stream_block_name':1, \ - 'tx_frame_count': 2, 'rx_frame_count': 3, \ - 'tx_frame_rate': 5, 'rx_frame_rate': 6, - 'frame_loss_percent': 7} - - # if specific stream block result can be found - if target_row: - if not (column_field in value_dict.keys()): - log.error("'{}' data is not in the results.".format(column_field)) - raise GenieTgnError("Unable to get '{}' data results.".format(column_field)) - else: - return target_row[value_dict[column_field]] - - @BaseConnection.locked @isconnected def set_line_rate(self, traffic_stream, rate, flow_group='', stop_traffic_time=15, \ @@ -1436,7 +1413,9 @@ def start_packet_capture(self, capture_time=60): log.info("Starting packet capture...") try: - self.stc.perform('CaptureStartAllCommand', CaptureProxyIds='project1') + ports = self.stc.get('Project1', 'children-port') + ports_list = [] if len(ports) == 0 else ports.split(' ') + self.stc.perform('CaptureStartAllCommand', CaptureProxyIds=ports_list) except Exception as e: log.error(e) raise GenieTgnError("Cannot start capture for all ports") from e @@ -1458,7 +1437,9 @@ def stop_packet_capture(self): log.info("Stop packet capture...") try: - self.stc.perform('CaptureStopAllCommand', CaptureProxyIds='project1') + ports = self.stc.get('Project1', 'children-port') + ports_list = [] if len(ports) == 0 else ports.split(' ') + self.stc.perform('CaptureStopAllCommand', CaptureProxyIds=ports_list) except Exception as e: raise GenieTgnError("Cannot stop capture for all ports") from e @@ -1513,6 +1494,11 @@ def save_packet_capture_file(self, port_name, pcap_type, filename, directory='/t # replace spaces in the portname, e.g PortConfig1 //10.109.125.240/1/1 port_name_str = re.sub(r"\s//.*", "", port_name) port_name_str = re.sub(r"\s", "_", port_name_str) + port_name_str = re.sub(r" ", "_", port_name_str) + # replace special character with '_' to avoid save file failure. + pattern = r'[/\\~!@#$%^&*()+=?><.,\[${}]' + port_name_str = re.sub(pattern, "_", port_name_str) + port_name_str = re.sub(r'_+', '_', port_name_str) cap_filename = '{port_name_str}_{pcap}_{f}.cap'.format(port_name_str=port_name_str, pcap=pcap_dict[pcap_type], f=filename) saved_filename=os.path.join(directory, cap_filename) @@ -1674,3 +1660,63 @@ def get_layer2_bit_rate(self, traffic_stream, flow_group=''): log.warning("Layer2 bit rate for '{}' is inaccurate because the load unit is not layer2 bits per second.".format(traffic_stream)) return load + + def save_result_database(self, file_name, file_path): + # save all results database + try: + result_db_name = file_name + ".db" + self.stc.perform("SaveResultsCommand", CollectResult=True, LoopMode="APPEND", ResultFileName=result_db_name, SaveDetailedResults=True) + for db_file in self.stc.files(): + if "db" in db_file: + tmp_file = db_file.split("/")[-1] + local_file_path = os.path.join(file_path, tmp_file) + self.stc.download(file_name=db_file, save_as=local_file_path) + log.info("File stored under " + local_file_path) + except Exception as e: + log.error(e) + raise GenieTgnError("Failed to save download file {} to {}".format(file_name+".db", file_path)) from e + + + @BaseConnection.locked + @isconnected + def save_statistics_snapshot_csv(self, view_name, csv_save_path="./", csv_file_name="result_statistics.csv"): + try: + csv_file = os.path.join(csv_save_path, csv_file_name) + if not self.use_iq: + # if data is not available. Need to subscribe data firstly. + + if self.drv == None or self.drv_result == None: + self.create_genie_dynamic_view() + + # if not subscribe + if self.stc.get(self.drv, "ResultState") == "NONE": + self.stc.perform("SubscribeDynamicResultViewCommand", DynamicResultView=self.drv) + + # get the result for drv + self.stc.perform("ExportResultsCommand", FileNamePrefix=csv_file_name.split(".")[0], OutputFormat="CSV", \ + ResultView=self.drv, WriteMode="APPEND") + + # undo subscribe for dynamicresultview and txstreamblockresults + self.stc.perform("UnsubscribeDynamicResultViewCommand", DynamicResultView = self.drv) + + config_file = self.stc.get("project1","ConfigurationFileName") + + file_name = os.path.join(".".join(os.path.basename(config_file).split(".")[0:-1]), csv_file_name) + self.stc.download(file_name, save_as=csv_file) + + else: + log.info("Store TestCenter IQ data") + rows = self.get_data_from_testcenter_iq() + columns = [["StreamBlock ID", "StreamBlock Name", "Tx Port Name", "Rx Port Name", "TxFrameCount (Frames)", \ + "RxSigFrameCount (Frames) ", "TxFrameRate (fps)", "RxSigFrameRate (fps) ", \ + "DroppedFramePercent", "Drop Count (Frames)", "Test Name"]] + + with open(csv_file, 'w', newline='') as file: + writer = csv.writer(file) + writer.writerows(columns+rows) + + log.info("File stored under " + csv_file) + except Exception as e: + log.error(e) + raise GenieTgnError("Unable to save statistics to '{}'".format(csv_save_path)) from e + diff --git a/src/genie/trafficgen/spirent/iq_files/streamblock.json b/src/genie/trafficgen/spirent/iq_files/streamblock.json index ee1a385..4508fd4 100644 --- a/src/genie/trafficgen/spirent/iq_files/streamblock.json +++ b/src/genie/trafficgen/spirent/iq_files/streamblock.json @@ -1,88 +1,84 @@ { - "multi_result": { + "multi_result": { "filters": [], "groups": [], "orders": [ - "view.stream_block_name_str_order ASC", - "view.stream_block_name_num_order ASC" + "view.tx_stream_stream_id ASC", + "view.rx_stream_key ASC" ], "projections": [ - "view.stream_block_name as stream_block_name", - "view.tx_port_name as tx_port_name", - "view.rx_port_name as rx_port_name", - "view.tx_stream_stats_frame_count as tx_stream_stats_frame_count", - "view.rx_stream_stats_frame_count as rx_stream_stats_frame_count", - "view.tx_stream_stats_frame_rate as tx_stream_stats_frame_rate", - "view.rx_stream_stats_frame_rate as rx_stream_stats_frame_rate", - "view.stream_stats_frame_loss_percent as stream_stats_frame_loss_percent", - "view.test_name as test_name" + "view.tx_stream_stream_id as tx_stream_stream_id", + "view.stream_block_name as stream_block_name", + "view.tx_port_name as tx_port_name", + "view.rx_port_name as rx_port_name", + "view.tx_stream_stats_frame_count as tx_stream_stats_frame_count", + "view.rx_stream_stats_frame_count as rx_stream_stats_frame_count", + "view.tx_stream_stats_frame_rate as tx_stream_stats_frame_rate", + "view.rx_stream_stats_frame_rate as rx_stream_stats_frame_rate", + "view.rx_stream_stats_dropped_frame_percent as rx_stream_stats_dropped_frame_percent", + "view.rx_stream_stats_dropped_frame_count as rx_stream_stats_dropped_frame_count", + "view.rx_stream_key as rx_stream_key" ], "subqueries": [ - { + { "alias": "view", "filters": [ - "rxss.stream_block_name = txss.stream_block_name", - "rxss.tx_port_name = txss.tx_port_name", - "rxss.test_name = txss.test_name" + "rxss.tx_stream_stream_id=txss.tx_stream_stream_id" ], "groups": [], "projections": [ - "rxss.stream_block_name as stream_block_name", - "rxss.tx_port_name as tx_port_name", - "rxss.rx_port_name as rx_port_name", - "txss.frame_count as tx_stream_stats_frame_count", - "rxss.frame_count as rx_stream_stats_frame_count", - "txss.frame_rate as tx_stream_stats_frame_rate", - "rxss.frame_rate as rx_stream_stats_frame_rate", - "((100.0 /greatest(1,txss.frame_count)) * (greatest(0, (txss.frame_count - rxss.frame_count - (greatest(txss.frame_rate, rxss.frame_rate) * ( 4 + greatest(0,(txss.counter_timestamp - rxss.counter_timestamp)/40000000))))))) as stream_stats_frame_loss_percent", - "rxss.test_name as test_name", - "rxss.stream_block_name_str_order as stream_block_name_str_order", - "rxss.stream_block_name_num_order as stream_block_name_num_order" + "rxss.tx_stream_stream_id as tx_stream_stream_id", + "rxss.stream_block_name as stream_block_name", + "rxss.tx_port_name as tx_port_name", + "rxss.rx_port_name as rx_port_name", + "txss.frame_count as tx_stream_stats_frame_count", + "rxss.frame_count as rx_stream_stats_frame_count", + "txss.frame_rate as tx_stream_stats_frame_rate", + "rxss.frame_rate as rx_stream_stats_frame_rate", + "rxss.dropped_frame_percent as rx_stream_stats_dropped_frame_percent", + "rxss.dropped_frame_count as rx_stream_stats_dropped_frame_count", + "rxss.rx_stream_key as rx_stream_key" ], "subqueries": [ - { + { "alias": "rxss", "filters": [ - "rx_stream.is_flooded = false", - "rx_stream_live_stats$last.is_deleted = false" - ], - "groups": [ - "stream_block.name", - "tx_port.name", - "rx_port.name", - "test.name", - "stream_block.name_str_order", - "stream_block.name_num_order" + "rx_stream_live_stats$last.is_deleted = false" ], + "groups": [], "projections": [ - "sum(rx_stream_live_stats$last.frame_count) as frame_count", - "stream_block.name as stream_block_name", - "tx_port.name as tx_port_name", - "rx_port.name as rx_port_name", - "sum(rx_stream_live_stats$last.frame_rate) as frame_rate", - "MAX(rx_stream_live_stats$last.counter_timestamp) as counter_timestamp", - "test.name as test_name", - "stream_block.name_str_order as stream_block_name_str_order", - "stream_block.name_num_order as stream_block_name_num_order" + "stream_block.name as stream_block_name", + "tx_stream.stream_id as tx_stream_stream_id", + "tx_port.name as tx_port_name", + "rx_port.name as rx_port_name", + "(rx_stream_live_stats$last.frame_count) as frame_count", + "(rx_stream_live_stats$last.out_seq_frame_count) as out_seq_frame_count", + "(rx_stream_live_stats$last.fcs_error_frame_count) as fcs_error_frame_count", + "(rx_stream_live_stats$last.ipv4_checksum_error_count) as ipv4_checksum_error_count", + "(rx_stream_live_stats$last.prbs_error_frame_count) as prbs_error_frame_count", + "(rx_stream_live_stats$last.tcp_udp_checksum_error_count) as tcp_udp_checksum_error_count", + "(rx_stream_live_stats$last.frame_rate) as frame_rate", + "((rx_stream_live_stats$last.dropped_frame_count*100.0)/(rx_stream_live_stats$last.sig_frame_count+rx_stream_live_stats$last.dropped_frame_count-rx_stream_live_stats$last.duplicate_frame_count)) as dropped_frame_percent", + "(rx_stream_live_stats$last.dropped_frame_count) as dropped_frame_count", + "rx_stream.key as rx_stream_key" ] - }, - { + }, + { "alias": "txss", "filters": [ - "tx_stream_live_stats$last.is_deleted = false" - ], - "groups": [ - "stream_block.name", - "tx_port.name", - "test.name" + "tx_stream_live_stats$last.is_deleted = false" ], + "groups": [], "projections": [ - "sum(tx_stream_live_stats$last.frame_count) as frame_count", - "stream_block.name as stream_block_name", - "tx_port.name as tx_port_name", - "sum(tx_stream_live_stats$last.frame_rate) as frame_rate", - "MAX(tx_stream_live_stats$last.counter_timestamp) as counter_timestamp", - "test.name as test_name" - ]}]}] - } -} \ No newline at end of file + "stream_block.name as stream_block_name", + "tx_stream.stream_id as tx_stream_stream_id", + "tx_port.name as tx_port_name", + "(tx_stream_live_stats$last.frame_count) as frame_count", + "(tx_stream_live_stats$last.frame_rate) as frame_rate" + ] + } + ] + } + ] + } +}