1
0
mirror of https://github.com/craigerl/aprsd.git synced 2025-07-30 20:32:27 -04:00

Compare commits

...

5 Commits

Author SHA1 Message Date
98a62102b7 Don't break logging aprslib failures
this patch removes the newline when logging failures to parse
aprs packets in aprslib
2024-11-08 13:47:02 -05:00
7d1e739502 Added new features to listen command.
Changed the default to not log incoming packets.  If you want to see
the packets logged, then pass in --log-packets.

Added the ability to specify a list of plugins to load by passing in
--enable-plugin <fully qualified python path to class>
You can specify --enable-plugin multiple times to enable multiple
plugins.

Added new switch to enable the packet stats thread logging of stats
of all the packets seen.  --enable-packet-stats.  This is off by
default.
2024-11-08 13:28:46 -05:00
bd0bcc1924 Fixed the protocol for Stats Collector
The stats() method had an inconsistent name for serializable.
2024-11-08 13:22:53 -05:00
adcf94d8c7 Catch and log exceptions in consumer
This patch adds a try except block around the APRSIS
consumer.  This gives us a chance to log the specific
exception, so we can see why the consumer failed.
2024-11-08 13:21:38 -05:00
9f3c8f889f Allow loading a specific list of plugins
Updated the PluginManager to allow only activating a
specific list of plugins passed in, instead of what is
in the config file.
2024-11-08 13:20:42 -05:00
5 changed files with 69 additions and 18 deletions

View File

@ -126,7 +126,10 @@ class APRSISClient(base.APRSClient):
return aprs_client
def consumer(self, callback, blocking=False, immortal=False, raw=False):
self._client.consumer(
callback, blocking=blocking,
immortal=immortal, raw=raw,
)
try:
self._client.consumer(
callback, blocking=blocking,
immortal=immortal, raw=raw,
)
except Exception as e:
LOG.error(f"Exception in consumer: {e}")

View File

@ -193,14 +193,14 @@ class Aprsdis(aprslib.IS):
except ParseError as exp:
self.logger.log(
11,
"%s\n Packet: %s",
"%s Packet: '%s'",
exp,
exp.packet,
)
except UnknownFormat as exp:
self.logger.log(
9,
"%s\n Packet: %s",
"%s Packet: '%s'",
exp,
exp.packet,
)

View File

@ -50,12 +50,16 @@ def signal_handler(sig, frame):
class APRSDListenThread(rx.APRSDRXThread):
def __init__(self, packet_queue, packet_filter=None, plugin_manager=None):
def __init__(
self, packet_queue, packet_filter=None, plugin_manager=None,
enabled_plugins=[], log_packets=False,
):
super().__init__(packet_queue)
self.packet_filter = packet_filter
self.plugin_manager = plugin_manager
if self.plugin_manager:
LOG.info(f"Plugins {self.plugin_manager.get_message_plugins()}")
self.log_packets = log_packets
def process_packet(self, *args, **kwargs):
packet = self._client.decode_packet(*args, **kwargs)
@ -76,13 +80,16 @@ class APRSDListenThread(rx.APRSDRXThread):
if self.packet_filter:
filter_class = filters[self.packet_filter]
if isinstance(packet, filter_class):
packet_log.log(packet)
if self.log_packets:
packet_log.log(packet)
if self.plugin_manager:
# Don't do anything with the reply
# This is the listen only command.
self.plugin_manager.run(packet)
else:
packet_log.log(packet)
if self.log_packets:
LOG.error("PISS")
packet_log.log(packet)
if self.plugin_manager:
# Don't do anything with the reply.
# This is the listen only command.
@ -95,7 +102,7 @@ class ListenStatsThread(APRSDThread):
"""Log the stats from the PacketList."""
def __init__(self):
super().__init__("SimpleStatsLog")
super().__init__("PacketStatsLog")
self._last_total_rx = 0
def loop(self):
@ -161,6 +168,11 @@ class ListenStatsThread(APRSDThread):
),
help="Filter by packet type",
)
@click.option(
"--enable-plugin",
multiple=True,
help="Enable a plugin. This is the name of the file in the plugins directory.",
)
@click.option(
"--load-plugins",
default=False,
@ -172,6 +184,18 @@ class ListenStatsThread(APRSDThread):
nargs=-1,
required=True,
)
@click.option(
"--log-packets",
default=False,
is_flag=True,
help="Log incoming packets.",
)
@click.option(
"--enable-packet-stats",
default=False,
is_flag=True,
help="Enable packet stats periodic logging.",
)
@click.pass_context
@cli_helper.process_standard_options
def listen(
@ -179,8 +203,11 @@ def listen(
aprs_login,
aprs_password,
packet_filter,
enable_plugin,
load_plugins,
filter,
log_packets,
enable_packet_stats,
):
"""Listen to packets on the APRS-IS Network based on FILTER.
@ -240,15 +267,26 @@ def listen(
packet_collector.PacketCollector().unregister(seen_list.SeenList)
pm = None
pm = plugin.PluginManager()
if load_plugins:
pm = plugin.PluginManager()
LOG.info("Loading plugins")
pm.setup_plugins(load_help_plugin=False)
elif enable_plugin:
pm = plugin.PluginManager()
pm.setup_plugins(
load_help_plugin=False,
plugin_list=enable_plugin,
)
else:
LOG.warning(
"Not Loading any plugins use --load-plugins to load what's "
"defined in the config file.",
)
if pm:
for p in pm.get_plugins():
LOG.info("Loaded plugin %s", p.__class__.__name__)
stats = stats_thread.APRSDStatsStoreThread()
stats.start()
@ -257,11 +295,14 @@ def listen(
packet_queue=threads.packet_queue,
packet_filter=packet_filter,
plugin_manager=pm,
enabled_plugins=enable_plugin,
log_packets=log_packets,
)
LOG.debug("Start APRSDListenThread")
listen_thread.start()
listen_stats = ListenStatsThread()
listen_stats.start()
if enable_packet_stats:
listen_stats = ListenStatsThread()
listen_stats.start()
keepalive.start()
LOG.debug("keepalive Join")

View File

@ -472,7 +472,10 @@ class PluginManager:
del self._pluggy_pm
self.setup_plugins()
def setup_plugins(self, load_help_plugin=True):
def setup_plugins(
self, load_help_plugin=True,
plugin_list=[],
):
"""Create the plugin manager and register plugins."""
LOG.info("Loading APRSD Plugins")
@ -481,9 +484,13 @@ class PluginManager:
_help = HelpPlugin()
self._pluggy_pm.register(_help)
enabled_plugins = CONF.enabled_plugins
if enabled_plugins:
for p_name in enabled_plugins:
# if plugins_list is passed in, only load
# those plugins.
if plugin_list:
for plugin_name in plugin_list:
self._load_plugin(plugin_name)
elif CONF.enabled_plugins:
for p_name in CONF.enabled_plugins:
self._load_plugin(p_name)
else:
# Enabled plugins isn't set, so we default to loading all of

View File

@ -10,7 +10,7 @@ LOG = logging.getLogger("APRSD")
@runtime_checkable
class StatsProducer(Protocol):
"""The StatsProducer protocol is used to define the interface for collecting stats."""
def stats(self, serializeable=False) -> dict:
def stats(self, serializable=False) -> dict:
"""provide stats in a dictionary format."""
...