Added live traffic stats counting and output to rnstatus

This commit is contained in:
Mark Qvist 2025-01-11 19:30:00 +01:00
parent 45494f21aa
commit ab5fcd7a5b
4 changed files with 106 additions and 10 deletions

View File

@ -172,8 +172,8 @@ class Reticulum:
RNS.Transport.exit_handler() RNS.Transport.exit_handler()
RNS.Identity.exit_handler() RNS.Identity.exit_handler()
if RNS.Profiler.ran(): # if RNS.Profiler.ran():
RNS.Profiler.results() # RNS.Profiler.results()
@staticmethod @staticmethod
def sigint_handler(signal, frame): def sigint_handler(signal, frame):
@ -965,6 +965,18 @@ class Reticulum:
else: else:
ifstats["bitrate"] = None ifstats["bitrate"] = None
if hasattr(interface, "current_rx_speed"):
if interface.current_rx_speed != None:
ifstats["rxs"] = interface.current_rx_speed
else:
ifstats["rxs"] = 0
if hasattr(interface, "current_tx_speed"):
if interface.current_tx_speed != None:
ifstats["txs"] = interface.current_tx_speed
else:
ifstats["txs"] = 0
if hasattr(interface, "peers"): if hasattr(interface, "peers"):
if interface.peers != None: if interface.peers != None:
ifstats["peers"] = len(interface.peers) ifstats["peers"] = len(interface.peers)
@ -1002,6 +1014,10 @@ class Reticulum:
stats = {} stats = {}
stats["interfaces"] = interfaces stats["interfaces"] = interfaces
stats["rxb"] = RNS.Transport.traffic_rxb
stats["txb"] = RNS.Transport.traffic_txb
stats["rxs"] = RNS.Transport.speed_rx
stats["txs"] = RNS.Transport.speed_tx
if Reticulum.transport_enabled(): if Reticulum.transport_enabled():
stats["transport_id"] = RNS.Transport.identity.hash stats["transport_id"] = RNS.Transport.identity.hash
stats["transport_uptime"] = time.time()-RNS.Transport.start_time stats["transport_uptime"] = time.time()-RNS.Transport.start_time

View File

@ -142,6 +142,12 @@ class Transport:
interface_last_jobs = 0.0 interface_last_jobs = 0.0
interface_jobs_interval = 5.0 interface_jobs_interval = 5.0
traffic_rxb = 0
traffic_txb = 0
speed_rx = 0
speed_tx = 0
traffic_captured = None
identity = None identity = None
@staticmethod @staticmethod
@ -195,6 +201,9 @@ class Transport:
thread = threading.Thread(target=Transport.jobloop, daemon=True) thread = threading.Thread(target=Transport.jobloop, daemon=True)
thread.start() thread.start()
thread = threading.Thread(target=Transport.count_traffic_loop, daemon=True)
thread.start()
if RNS.Reticulum.transport_enabled(): if RNS.Reticulum.transport_enabled():
destination_table_path = RNS.Reticulum.storagepath+"/destination_table" destination_table_path = RNS.Reticulum.storagepath+"/destination_table"
tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels" tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels"
@ -321,6 +330,40 @@ class Transport:
except Exception as e: except Exception as e:
RNS.log(f"Could not prioritize interfaces according to bitrate. The contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"Could not prioritize interfaces according to bitrate. The contained exception was: {e}", RNS.LOG_ERROR)
@staticmethod
def count_traffic_loop():
while True:
time.sleep(1)
try:
rxb = 0; txb = 0;
rxs = 0; txs = 0;
for interface in Transport.interfaces:
if not hasattr(interface, "parent_interface") or interface.parent_interface == None:
if hasattr(interface, "transport_traffic_counter"):
now = time.time(); irxb = interface.rxb; itxb = interface.txb
tc = interface.transport_traffic_counter
rx_diff = irxb - tc["rxb"]
tx_diff = itxb - tc["txb"]
ts_diff = now - tc["ts"]
rxb += rx_diff; crxs = (rx_diff*8)/ts_diff
txb += tx_diff; ctxs = (tx_diff*8)/ts_diff
interface.current_rx_speed = crxs; rxs += crxs
interface.current_tx_speed = ctxs; txs += ctxs
tc["rxb"] = irxb;
tc["txb"] = itxb;
tc["ts"] = now;
else:
interface.transport_traffic_counter = {"ts": time.time(), "rxb": interface.rxb, "txb": interface.txb}
Transport.traffic_rxb += rxb
Transport.traffic_txb += txb
Transport.speed_rx = rxs
Transport.speed_tx = txs
except Exception as e:
RNS.log(f"An error occurred while counting interface traffic: {e}", RNS.LOG_ERROR)
@staticmethod @staticmethod
def jobloop(): def jobloop():
while (True): while (True):

View File

@ -135,7 +135,7 @@ def get_remote_status(destination_hash, include_lstats, identity, no_output=Fals
def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False, def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False,
lstats=False, sorting=None, sort_reverse=False, remote=None, management_identity=None, lstats=False, sorting=None, sort_reverse=False, remote=None, management_identity=None,
remote_timeout=RNS.Transport.PATH_REQUEST_TIMEOUT, must_exit=True, rns_instance=None): remote_timeout=RNS.Transport.PATH_REQUEST_TIMEOUT, must_exit=True, rns_instance=None, traffic_totals=False):
if remote: if remote:
require_shared = False require_shared = False
@ -228,6 +228,10 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
interfaces.sort(key=lambda i: i["rxb"], reverse=not sort_reverse) interfaces.sort(key=lambda i: i["rxb"], reverse=not sort_reverse)
if sorting == "tx": if sorting == "tx":
interfaces.sort(key=lambda i: i["txb"], reverse=not sort_reverse) interfaces.sort(key=lambda i: i["txb"], reverse=not sort_reverse)
if sorting == "rxs":
interfaces.sort(key=lambda i: i["rxs"], reverse=not sort_reverse)
if sorting == "txs":
interfaces.sort(key=lambda i: i["txs"], reverse=not sort_reverse)
if sorting == "traffic": if sorting == "traffic":
interfaces.sort(key=lambda i: i["rxb"]+i["txb"], reverse=not sort_reverse) interfaces.sort(key=lambda i: i["rxb"]+i["txb"], reverse=not sort_reverse)
if sorting == "announces" or sorting == "announce": if sorting == "announces" or sorting == "announce":
@ -364,7 +368,18 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
print(" Announces : {iaf}".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"]))) print(" Announces : {iaf}".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"])))
print(" {iaf}".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"]))) print(" {iaf}".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"])))
print(" Traffic : {txb}\n {rxb}".format(rxb=size_str(ifstat["rxb"]), txb=size_str(ifstat["txb"]))) rxb_str = ""+RNS.prettysize(ifstat["rxb"])
txb_str = ""+RNS.prettysize(ifstat["txb"])
strdiff = len(rxb_str)-len(txb_str)
if strdiff > 0:
txb_str += " "*strdiff
elif strdiff < 0:
rxb_str += " "*-strdiff
rxstat = rxb_str+" "+RNS.prettyspeed(ifstat["rxs"])
txstat = txb_str+" "+RNS.prettyspeed(ifstat["txs"])
print(f" Traffic : {txstat}\n {rxstat}")
lstr = "" lstr = ""
if link_count != None and lstats: if link_count != None and lstats:
@ -374,6 +389,19 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
else: else:
lstr = f" {link_count} entr{ms} in link table" lstr = f" {link_count} entr{ms} in link table"
if traffic_totals:
rxb_str = ""+RNS.prettysize(stats["rxb"])
txb_str = ""+RNS.prettysize(stats["txb"])
strdiff = len(rxb_str)-len(txb_str)
if strdiff > 0:
txb_str += " "*strdiff
elif strdiff < 0:
rxb_str += " "*-strdiff
rxstat = rxb_str+" "+RNS.prettyspeed(stats["rxs"])
txstat = txb_str+" "+RNS.prettyspeed(stats["txs"])
print(f"\n Totals : {txstat}\n {rxstat}")
if "transport_id" in stats and stats["transport_id"] != None: if "transport_id" in stats and stats["transport_id"] != None:
print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running") print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running")
if "probe_responder" in stats and stats["probe_responder"] != None: if "probe_responder" in stats and stats["probe_responder"] != None:
@ -426,11 +454,19 @@ def main(must_exit=True, rns_instance=None):
default=False, default=False,
) )
parser.add_argument(
"-t",
"--totals",
action="store_true",
help="display traffic totals",
default=False,
)
parser.add_argument( parser.add_argument(
"-s", "-s",
"--sort", "--sort",
action="store", action="store",
help="sort interfaces by [rate, traffic, rx, tx, announces, arx, atx, held]", help="sort interfaces by [rate, traffic, rx, tx, rxs, txs, announces, arx, atx, held]",
default=None, default=None,
type=str type=str
) )
@ -504,6 +540,7 @@ def main(must_exit=True, rns_instance=None):
remote_timeout=args.w, remote_timeout=args.w,
must_exit=must_exit, must_exit=must_exit,
rns_instance=rns_instance, rns_instance=rns_instance,
traffic_totals=args.totals,
) )
except KeyboardInterrupt: except KeyboardInterrupt: