diff --git a/aprsd/cmds/listen.py b/aprsd/cmds/listen.py
index 646d3c9..60f48c5 100644
--- a/aprsd/cmds/listen.py
+++ b/aprsd/cmds/listen.py
@@ -10,12 +10,13 @@ import sys
import time
import click
+from loguru import logger
from oslo_config import cfg
from rich.console import Console
# local imports here
import aprsd
-from aprsd import cli_helper, packets, plugin, threads
+from aprsd import cli_helper, packets, plugin, threads, utils
from aprsd.client import client_factory
from aprsd.main import cli
from aprsd.packets import collector as packet_collector
@@ -24,12 +25,14 @@ from aprsd.packets import seen_list
from aprsd.stats import collector
from aprsd.threads import keep_alive, rx
from aprsd.threads import stats as stats_thread
+from aprsd.threads.aprsd import APRSDThread
# setup the global logger
# log.basicConfig(level=log.DEBUG) # level=10
LOG = logging.getLogger("APRSD")
CONF = cfg.CONF
+LOGU = logger
console = Console()
@@ -46,6 +49,41 @@ def signal_handler(sig, frame):
collector.Collector().collect()
+@utils.singleton
+class SimplePacketStats:
+ def __init__(self):
+ self.total_rx = 0
+ self.total_tx = 0
+ self.types = {}
+
+ def rx(self, packet):
+ self.total_rx += 1
+ ptype = packet.__class__.__name__
+ if ptype not in self.types:
+ self.types[ptype] = {"tx": 0, "rx": 0}
+ self.types[ptype]["rx"] += 1
+
+ def tx(self, packet):
+ self.total_tx += 1
+ ptype = packet.__class__.__name__
+ if ptype not in self.types:
+ self.types[ptype] = {"tx": 0, "rx": 0}
+ self.types[ptype]["tx"] += 1
+
+ def flush(self):
+ pass
+
+ def load(self):
+ pass
+
+ def stats(self, serializable=False):
+ return {
+ "total_rx": self.total_rx,
+ "total_tx": self.total_tx,
+ "types": self.types,
+ }
+
+
class APRSDListenThread(rx.APRSDRXThread):
def __init__(self, packet_queue, packet_filter=None, plugin_manager=None):
super().__init__(packet_queue)
@@ -88,6 +126,28 @@ class APRSDListenThread(rx.APRSDRXThread):
packet_collector.PacketCollector().rx(packet)
+class ListenStatsThread(APRSDThread):
+ def __init__(self):
+ super().__init__("SimpleStats")
+ self._last_total_rx = 0
+
+ def loop(self):
+ if self.loop_count % 10 == 0:
+ # log the stats every 10 seconds
+ stats_json = collector.Collector().collect()
+ stats = stats_json["SimplePacketStats"]
+ total_rx = stats["total_rx"]
+ rate = (total_rx - self._last_total_rx) / 10
+ LOG.warning(f"RX Rate: {rate} pps Total RX: {total_rx} - {self._last_total_rx}")
+ #LOG.error(stats)
+ self._last_total_rx = total_rx
+ for k, v in stats["types"].items():
+ LOGU.opt(colors=True).warning(f"Type: {k} RX: {v['rx']} TX: {v['tx']}")
+
+ time.sleep(1)
+ return True
+
+
@cli.command()
@cli_helper.add_options(cli_helper.common_options)
@click.option(
@@ -201,6 +261,27 @@ def listen(
# just deregister the class from the packet collector
packet_collector.PacketCollector().unregister(seen_list.SeenList)
+ packet_collector.PacketCollector().register(SimplePacketStats)
+
+ from aprsd.client import stats as client_stats
+ from aprsd.packets.packet_list import PacketList # noqa: F401
+ from aprsd.packets.seen_list import SeenList # noqa: F401
+ from aprsd.packets.tracker import PacketTrack # noqa: F401
+ from aprsd.packets.watch_list import WatchList # noqa: F401
+ from aprsd.plugins import email
+ from aprsd.threads import aprsd as aprsd_thread
+ c = collector.Collector()
+ # c.unregister_producer(app.APRSDStats)
+ c.unregister_producer(PacketList)
+ c.unregister_producer(WatchList)
+ #c.unregister_producer(PacketTrack)
+ c.unregister_producer(plugin.PluginManager)
+ c.unregister_producer(aprsd_thread.APRSDThreadList)
+ c.unregister_producer(email.EmailStats)
+ c.unregister_producer(client_stats.APRSClientStats)
+ c.unregister_producer(seen_list.SeenList)
+ c.register_producer(SimplePacketStats)
+
pm = None
pm = plugin.PluginManager()
if load_plugins:
@@ -222,6 +303,8 @@ def listen(
)
LOG.debug("Start APRSDListenThread")
listen_thread.start()
+ listen_stats = ListenStatsThread()
+ listen_stats.start()
keepalive.start()
LOG.debug("keepalive Join")
diff --git a/aprsd/stats/collector.py b/aprsd/stats/collector.py
index c3da428..d899031 100644
--- a/aprsd/stats/collector.py
+++ b/aprsd/stats/collector.py
@@ -35,3 +35,8 @@ class Collector:
if not isinstance(producer_name, StatsProducer):
raise TypeError(f"Producer {producer_name} is not a StatsProducer")
self.producers.append(producer_name)
+
+ def unregister_producer(self, producer_name: Callable):
+ if not isinstance(producer_name, StatsProducer):
+ raise TypeError(f"Producer {producer_name} is not a StatsProducer")
+ self.producers.remove(producer_name)