diff --git a/ogn/gateway/__init__.py b/ogn/gateway/__init__.py index 522a6b2..ec585e4 100644 --- a/ogn/gateway/__init__.py +++ b/ogn/gateway/__init__.py @@ -5,6 +5,7 @@ from ogn.gateway import settings from ogn.commands.dbutils import session from ogn.aprs_parser import parse_aprs from ogn.exceptions import AprsParseError, OgnParseError +from ogn.logger import logger from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker @@ -21,8 +22,6 @@ class ognGateway: self.session = session def connect(self, aprs_user): - if len(aprs_user) < 3 or len(aprs_user) > 9: - print("aprs_user must be a string of 3-9 characters") # create socket, connect to server, login and make a file object associated with the socket self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) @@ -34,14 +33,14 @@ class ognGateway: def disconnect(self): # close everything - print('Close socket') self.sock.shutdown(0) self.sock.close() def run(self): keepalive_time = time() while True: - if time() - keepalive_time > 60: + if time() - keepalive_time > settings.APRS_KEEPALIVE_TIME: + logger.debug('Sending keepalive') self.sock.send("#keepalive".encode()) keepalive_time = time() @@ -51,7 +50,7 @@ class ognGateway: # A zero length line should not be return if keepalives are being sent # A zero length line will only be returned after ~30m if keepalives are not sent if len(packet_str) == 0: - print('Read returns zero length string. Failure. Orderly closeout') + logger.warning('Read returns zero length string. Failure. Orderly closeout') break self.proceed_line(packet_str) @@ -59,12 +58,11 @@ class ognGateway: def proceed_line(self, line): try: beacon = parse_aprs(line) - except AprsParseError as e: - print(e.message) + except AprsParseError: + logger.error('AprsParseError', exc_info=True) return - except OgnParseError as e: - print(e.message) - print("APRS line: %s" % line) + except OgnParseError: + logger.error('OgnParseError', exc_info=True) return if beacon is not None: diff --git a/ogn/gateway/manage.py b/ogn/gateway/manage.py index 2e4a85d..ce50a83 100644 --- a/ogn/gateway/manage.py +++ b/ogn/gateway/manage.py @@ -1,6 +1,7 @@ import socket from ogn.gateway import ognGateway +from ogn.logger import logger DB_URI = 'sqlite:///beacons.db' @@ -11,29 +12,37 @@ manager = Manager() @manager.command def run(aprs_user="anon-dev"): """Run the aprs client.""" + if len(aprs_user) < 3 or len(aprs_user) > 9: + print("aprs_user must be a string of 3-9 characters") + return + user_interrupted = False gateway = ognGateway() print("Connect to DB") + logger.info('Connect to DB') gateway.connect_db() while user_interrupted is False: - print("Connect OGN gateway as {}".format(aprs_user)) + logger.info("Connect OGN gateway as {}".format(aprs_user)) gateway.connect(aprs_user) - socket_open = True try: + logger.info('Run gateway') gateway.run() except KeyboardInterrupt: - print("User interrupted") + logger.error('User interrupted', exc_info=True) user_interrupted = True except BrokenPipeError: - print("BrokenPipeError") + logger.error('BrokenPipeError', exc_info=True) except socket.error: - print("socket error") - socket_open = False + logger.error('Socket error', exc_info=True) - if socket_open: + try: + logger.info('Close socket') gateway.disconnect() + except OSError as e: + print('Socket close error: {}'.format(e.strerror)) + logger.error('Socket close error', exc_info=True) print("\nExit OGN gateway") diff --git a/ogn/gateway/settings.py b/ogn/gateway/settings.py index 3ccad01..3216638 100644 --- a/ogn/gateway/settings.py +++ b/ogn/gateway/settings.py @@ -4,3 +4,4 @@ APRS_USER = 'PyGrabber' APRS_PASSCODE = -1 # Read only APRS_FILTER = "filter r/+50.0000/+10.0000/5000" +APRS_KEEPALIVE_TIME = 240 diff --git a/ogn/logger.py b/ogn/logger.py new file mode 100644 index 0000000..3809228 --- /dev/null +++ b/ogn/logger.py @@ -0,0 +1,17 @@ +import logging + +logger = logging.getLogger('main') +logger.setLevel(logging.DEBUG) + +filehandler = logging.FileHandler('main.log') +filehandler.setLevel(logging.DEBUG) + +consolehandler = logging.StreamHandler() +consolehandler.setLevel(logging.INFO) + +formatter = logging.Formatter("%(asctime)s - %(levelname).4s - %(name)s - %(message)s") +filehandler.setFormatter(formatter) +consolehandler.setFormatter(formatter) + +logger.addHandler(filehandler) +logger.addHandler(consolehandler) diff --git a/tests/gateway/test_manage.py b/tests/gateway/test_manage.py index b3a4bb0..ac633c9 100644 --- a/tests/gateway/test_manage.py +++ b/tests/gateway/test_manage.py @@ -10,7 +10,7 @@ class GatewayTest(unittest.TestCase): # try simple user interrupt @mock.patch('ogn.gateway.manage.ognGateway') - def test_user_interruption(self, mock_gateway): + def test_run_user_interruption(self, mock_gateway): instance = mock_gateway.return_value instance.run.side_effect = KeyboardInterrupt() @@ -23,7 +23,7 @@ class GatewayTest(unittest.TestCase): # make BrokenPipeErrors and a socket error (may happen) and then a user interrupt (important!) @mock.patch('ogn.gateway.manage.ognGateway') - def test_BrokenPipeError(self, mock_gateway): + def test_run_multiple_errors(self, mock_gateway): instance = mock_gateway.return_value instance.run.side_effect = [BrokenPipeError(), socket.error(), KeyboardInterrupt()] @@ -32,7 +32,7 @@ class GatewayTest(unittest.TestCase): instance.connect_db.assert_called_once_with() self.assertEqual(instance.connect.call_count, 3) self.assertEqual(instance.run.call_count, 3) - self.assertEqual(instance.disconnect.call_count, 2) # not called if socket crashed + self.assertEqual(instance.disconnect.call_count, 3) if __name__ == '__main__': unittest.main()