diff --git a/aprsd/conf/common.py b/aprsd/conf/common.py index dc27776..877d49a 100644 --- a/aprsd/conf/common.py +++ b/aprsd/conf/common.py @@ -101,6 +101,14 @@ aprsd_opts = [ default=None, help="Longitude for the GPS Beacon button. If not set, the button will not be enabled.", ), + cfg.StrOpt( + "log_packet_format", + choices=["compact", "multiline", "both"], + default="compact", + help="When logging packets 'compact' will use a single line formatted for each packet." + "'multiline' will use multiple lines for each packet and is the traditional format." + "both will log both compact and multiline.", + ), ] watch_list_opts = [ diff --git a/aprsd/packets/log.py b/aprsd/packets/log.py new file mode 100644 index 0000000..b46e957 --- /dev/null +++ b/aprsd/packets/log.py @@ -0,0 +1,125 @@ +import logging +from typing import Optional + +from loguru import logger +from oslo_config import cfg + +from aprsd.packets.core import AckPacket, RejectPacket + + +LOG = logging.getLogger() +LOGU = logger +CONF = cfg.CONF + +FROM_COLOR = "fg #C70039" +TO_COLOR = "fg #D033FF" +TX_COLOR = "red" +RX_COLOR = "green" +PACKET_COLOR = "cyan" + + +def log_multiline(packet, tx: Optional[bool] = False, header: Optional[bool] = True) -> None: + """LOG a packet to the logfile.""" + if CONF.log_packet_format == "compact": + return + # asdict(packet) + logit = ["\n"] + name = packet.__class__.__name__ + if header: + if tx: + header_str = f"<{TX_COLOR}>TX" + logit.append( + f"{header_str}________(<{PACKET_COLOR}>{name} " + f"TX:{packet.send_count + 1} of {packet.retry_count})", + ) + else: + header_str = f"<{RX_COLOR}>RX" + logit.append( + f"{header_str}________(<{PACKET_COLOR}>{name})", + ) + + else: + header_str = "" + logit.append(f"__________(<{PACKET_COLOR}>{name})") + # log_list.append(f" Packet : {packet.__class__.__name__}") + if packet.msgNo: + logit.append(f" Msg # : {packet.msgNo}") + if packet.from_call: + logit.append(f" From : <{FROM_COLOR}>{packet.from_call}") + if packet.to_call: + logit.append(f" To : <{TO_COLOR}>{packet.to_call}") + if hasattr(packet, "path") and packet.path: + logit.append(f" Path : {'=>'.join(packet.path)}") + if hasattr(packet, "via") and packet.via: + logit.append(f" VIA : {packet.via}") + + if not isinstance(packet, AckPacket) and not isinstance(packet, RejectPacket): + msg = packet.human_info + + if msg: + msg = msg.replace("<", "\\<") + logit.append(f" Info : {msg}") + + raw = packet.raw.replace("<", "\\<") + logit.append(f" Raw : {raw}") + logit.append(f"{header_str}________(<{PACKET_COLOR}>{name})") + + LOGU.opt(colors=True).info("\n".join(logit)) + LOG.debug(repr(packet)) + + +def log(packet, tx: Optional[bool] = False, header: Optional[bool] = True) -> None: + if CONF.log_packet_format == "multiline": + log_multiline(packet, tx, header) + return + + logit = [] + name = packet.__class__.__name__ + + if header: + if tx: + via_color = "red" + arrow = f"<{via_color}>->" + logit.append( + f"TX {arrow} " + f"{name}" + f":{packet.msgNo}" + f" ({packet.send_count + 1} of {packet.retry_count})", + ) + else: + via_color = "fg #828282" + arrow = f"<{via_color}>->" + left_arrow = f"<{via_color}><-" + logit.append( + f"RX {left_arrow} " + f"{name}" + f":{packet.msgNo}", + ) + else: + via_color = "green" + arrow = f"<{via_color}>->" + logit.append( + f"{name}" + f":{packet.msgNo}", + ) + + tmp = None + if packet.path: + tmp = f"{arrow}".join(packet.path) + f"{arrow} " + + logit.append( + f"<{FROM_COLOR}>{packet.from_call} {arrow}" + f"{tmp if tmp else ' '}" + f"<{TO_COLOR}>{packet.to_call}", + ) + + if not isinstance(packet, AckPacket) and not isinstance(packet, RejectPacket): + logit.append(":") + msg = packet.human_info + + if msg: + msg = msg.replace("<", "\\<") + logit.append(f"{msg}") + + LOGU.opt(colors=True).info(" ".join(logit)) + log_multiline(packet, tx, header)