22
33#####################################################################
44#
5- # queuestat is a tool for summarizing queue statistics of all ports.
5+ # queuestat is a tool for summarizing queue statistics of all ports.
66#
77#####################################################################
88
99import _pickle as pickle
1010import argparse
1111import datetime
1212import os .path
13- from swsscommon .swsscommon import SonicV2Connector
1413import sys
1514
1615from collections import namedtuple , OrderedDict
1716from natsort import natsorted
1817from tabulate import tabulate
1918
19+ # mock the redis for unit test purposes #
20+ try :
21+ if os .environ ["UTILITIES_UNIT_TESTING" ] == "2" :
22+ modules_path = os .path .join (os .path .dirname (__file__ ), ".." )
23+ tests_path = os .path .join (modules_path , "tests" )
24+ sys .path .insert (0 , modules_path )
25+ sys .path .insert (0 , tests_path )
26+ import mock_tables .dbconnector # lgtm [py/unused-import]
27+
28+ except KeyError :
29+ pass
30+
31+ from swsscommon .swsscommon import SonicV2Connector
2032
2133QueueStats = namedtuple ("QueueStats" , "queueindex, queuetype, totalpacket, totalbytes, droppacket, dropbytes" )
2234header = ['Port' , 'TxQ' , 'Counter/pkts' , 'Counter/bytes' , 'Drop/pkts' , 'Drop/bytes' ]
@@ -28,6 +40,7 @@ counter_bucket_dict = {
2840 'SAI_QUEUE_STAT_DROPPED_BYTES' : 5 ,
2941}
3042
43+ from utilities_common .cli import json_dump
3144from utilities_common .netstat import ns_diff , STATUS_NA
3245
3346QUEUE_TYPE_MC = 'MC'
@@ -47,6 +60,24 @@ COUNTERS_QUEUE_PORT_MAP = "COUNTERS_QUEUE_PORT_MAP"
4760cnstat_dir = 'N/A'
4861cnstat_fqn_file = 'N/A'
4962
63+
64+ def build_json (port , cnstat ):
65+ def ports_stats (k ):
66+ p = {}
67+ p [k [1 ]] = {
68+ "totalpacket" : k [2 ],
69+ "totalbytes" : k [3 ],
70+ "droppacket" : k [4 ],
71+ "dropbytes" : k [5 ]
72+ }
73+ return p
74+
75+ out = {}
76+ for k in cnstat :
77+ out .update (ports_stats (k ))
78+ return out
79+
80+
5081class Queuestat (object ):
5182 def __init__ (self ):
5283 self .db = SonicV2Connector (use_unix_socket_path = False )
@@ -134,33 +165,45 @@ class Queuestat(object):
134165 if queue_map is None :
135166 return cnstat_dict
136167 for queue in natsorted (queue_map ):
137- cnstat_dict [queue ] = get_counters (queue_map [queue ])
168+ cnstat_dict [queue ] = get_counters (queue_map [queue ])
138169 return cnstat_dict
139170
140- def cnstat_print (self , port , cnstat_dict ):
171+ def cnstat_print (self , port , cnstat_dict , json_opt ):
141172 """
142- Print the cnstat.
173+ Print the cnstat. If JSON option is True, return data in
174+ JSON format.
143175 """
144176 table = []
177+ json_output = {port : {}}
145178
146179 for key , data in cnstat_dict .items ():
147180 if key == 'time' :
181+ if json_opt :
182+ json_output [port ][key ] = data
148183 continue
149184 table .append ((port , data .queuetype + str (data .queueindex ),
150185 data .totalpacket , data .totalbytes ,
151186 data .droppacket , data .dropbytes ))
152187
153- print (tabulate (table , header , tablefmt = 'simple' , stralign = 'right' ))
154- print ()
188+ if json_opt :
189+ json_output [port ].update (build_json (port , table ))
190+ return json_output
191+ else :
192+ print (tabulate (table , header , tablefmt = 'simple' , stralign = 'right' ))
193+ print ()
155194
156- def cnstat_diff_print (self , port , cnstat_new_dict , cnstat_old_dict ):
195+ def cnstat_diff_print (self , port , cnstat_new_dict , cnstat_old_dict , json_opt ):
157196 """
158- Print the difference between two cnstat results.
197+ Print the difference between two cnstat results. If JSON
198+ option is True, return data in JSON format.
159199 """
160200 table = []
201+ json_output = {port : {}}
161202
162203 for key , cntr in cnstat_new_dict .items ():
163204 if key == 'time' :
205+ if json_opt :
206+ json_output [port ][key ] = cntr
164207 continue
165208 old_cntr = None
166209 if key in cnstat_old_dict :
@@ -177,42 +220,78 @@ class Queuestat(object):
177220 cntr .totalpacket , cntr .totalbytes ,
178221 cntr .droppacket , cntr .dropbytes ))
179222
180- print (tabulate (table , header , tablefmt = 'simple' , stralign = 'right' ))
181- print ()
223+ if json_opt :
224+ json_output [port ].update (build_json (port , table ))
225+ return json_output
226+ else :
227+ print (tabulate (table , header , tablefmt = 'simple' , stralign = 'right' ))
228+ print ()
182229
183- def get_print_all_stat (self ):
184- # Get stat for each port
230+ def get_print_all_stat (self , json_opt ):
231+ """
232+ Get stat for each port
233+ If JSON option is True, collect data for each port and
234+ print data in JSON format for all ports
235+ """
236+ json_output = {}
185237 for port in natsorted (self .counter_port_name_map ):
238+ json_output [port ] = {}
186239 cnstat_dict = self .get_cnstat (self .port_queues_map [port ])
187240
188241 cnstat_fqn_file_name = cnstat_fqn_file + port
189242 if os .path .isfile (cnstat_fqn_file_name ):
190243 try :
191244 cnstat_cached_dict = pickle .load (open (cnstat_fqn_file_name , 'rb' ))
192- print (port + " Last cached time was " + str (cnstat_cached_dict .get ('time' )))
193- self .cnstat_diff_print (port , cnstat_dict , cnstat_cached_dict )
245+ if json_opt :
246+ json_output [port ].update ({"cached_time" :cnstat_cached_dict .get ('time' )})
247+ json_output .update (self .cnstat_diff_print (port , cnstat_dict , cnstat_cached_dict , json_opt ))
248+ else :
249+ print (port + " Last cached time was " + str (cnstat_cached_dict .get ('time' )))
250+ self .cnstat_diff_print (port , cnstat_dict , cnstat_cached_dict , json_opt )
194251 except IOError as e :
195252 print (e .errno , e )
196253 else :
197- self .cnstat_print (port , cnstat_dict )
254+ if json_opt :
255+ json_output .update (self .cnstat_print (port , cnstat_dict , json_opt ))
256+ else :
257+ self .cnstat_print (port , cnstat_dict , json_opt )
198258
199- def get_print_port_stat (self , port ):
259+ if json_opt :
260+ print (json_dump (json_output ))
261+
262+ def get_print_port_stat (self , port , json_opt ):
263+ """
264+ Get stat for the port
265+ If JSON option is True print data in JSON format
266+ """
200267 if not port in self .port_queues_map :
201268 print ("Port doesn't exist!" , port )
202269 sys .exit (1 )
203270
204271 # Get stat for the port queried
205272 cnstat_dict = self .get_cnstat (self .port_queues_map [port ])
206273 cnstat_fqn_file_name = cnstat_fqn_file + port
274+ json_output = {}
275+ json_output [port ] = {}
207276 if os .path .isfile (cnstat_fqn_file_name ):
208277 try :
209278 cnstat_cached_dict = pickle .load (open (cnstat_fqn_file_name , 'rb' ))
210- print ("Last cached time was " + str (cnstat_cached_dict .get ('time' )))
211- self .cnstat_diff_print (port , cnstat_dict , cnstat_cached_dict )
279+ if json_opt :
280+ json_output [port ].update ({"cached_time" :cnstat_cached_dict .get ('time' )})
281+ json_output .update (self .cnstat_diff_print (port , cnstat_dict , cnstat_cached_dict , json_opt ))
282+ else :
283+ print ("Last cached time was " + str (cnstat_cached_dict .get ('time' )))
284+ self .cnstat_diff_print (port , cnstat_dict , cnstat_cached_dict , json_opt )
212285 except IOError as e :
213286 print (e .errno , e )
214287 else :
215- self .cnstat_print (port , cnstat_dict )
288+ if json_opt :
289+ json_output .update (self .cnstat_print (port , cnstat_dict , json_opt ))
290+ else :
291+ self .cnstat_print (port , cnstat_dict , json_opt )
292+
293+ if json_opt :
294+ print (json_dump (json_output ))
216295
217296 def save_fresh_stats (self ):
218297 if not os .path .exists (cnstat_dir ):
@@ -251,10 +330,12 @@ Examples:
251330 parser .add_argument ('-c' , '--clear' , action = 'store_true' , help = 'Clear previous stats and save new ones' )
252331 parser .add_argument ('-d' , '--delete' , action = 'store_true' , help = 'Delete saved stats' )
253332 parser .add_argument ('-v' , '--version' , action = 'version' , version = '%(prog)s 1.0' )
333+ parser .add_argument ('-j' , '--json_opt' , action = 'store_true' , help = 'Print in JSON format' )
254334 args = parser .parse_args ()
255335
256336 save_fresh_stats = args .clear
257337 delete_all_stats = args .delete
338+ json_opt = args .json_opt
258339
259340 port_to_show_stats = args .port
260341
@@ -282,9 +363,9 @@ Examples:
282363 sys .exit (0 )
283364
284365 if port_to_show_stats != None :
285- queuestat .get_print_port_stat (port_to_show_stats )
366+ queuestat .get_print_port_stat (port_to_show_stats , json_opt )
286367 else :
287- queuestat .get_print_all_stat ()
368+ queuestat .get_print_all_stat (json_opt )
288369
289370 sys .exit (0 )
290371
0 commit comments