From 4fe0a297934807ff5d9dc984cbbb6ee3c1441b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Sun, 22 Nov 2015 21:11:55 +0100 Subject: [PATCH 1/2] Added logger --- ogn/gateway/__init__.py | 18 ++++++++---------- ogn/gateway/manage.py | 23 ++++++++++++++++------- ogn/gateway/settings.py | 1 + ogn/logger.py | 17 +++++++++++++++++ tests/gateway/test_manage.py | 6 +++--- 5 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 ogn/logger.py 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() From 3ab10cfb686bbc26b7c5175a57d9d153d66ceb8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Mon, 23 Nov 2015 20:40:44 +0100 Subject: [PATCH 2/2] Create aprs login string --- ogn/aprs_utils.py | 7 +++++++ ogn/gateway/__init__.py | 5 ++--- ogn/gateway/settings.py | 6 +++--- tests/test_aprs_utils.py | 10 +++++++++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/ogn/aprs_utils.py b/ogn/aprs_utils.py index b026aae..0fbdd25 100644 --- a/ogn/aprs_utils.py +++ b/ogn/aprs_utils.py @@ -34,3 +34,10 @@ def createTimestamp(hhmmss, reference): elif abs(reference.hour - hh) > 1: raise Exception("Time difference is too big. Reference time:%s - timestamp:%s" % (reference, hhmmss)) return datetime(reference.year, reference.month, reference.day, hh, mm, ss) + + +def create_aprs_login(user_name, pass_code, app_name, app_version, aprs_filter=None): + if not aprs_filter: + return "user %s pass %s vers %s %s\n" % (user_name, pass_code, app_name, app_version) + else: + return "user %s pass %s vers %s %s filter %s\n" % (user_name, pass_code, app_name, app_version, aprs_filter) diff --git a/ogn/gateway/__init__.py b/ogn/gateway/__init__.py index ec585e4..2a12b37 100644 --- a/ogn/gateway/__init__.py +++ b/ogn/gateway/__init__.py @@ -4,6 +4,7 @@ from time import time from ogn.gateway import settings from ogn.commands.dbutils import session from ogn.aprs_parser import parse_aprs +from ogn.aprs_utils import create_aprs_login from ogn.exceptions import AprsParseError, OgnParseError from ogn.logger import logger @@ -11,8 +12,6 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from ogn.model import Base -MODULE_VERSION = "0.1" - class ognGateway: def __init__(self): @@ -27,7 +26,7 @@ class ognGateway: self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) self.sock.connect((settings.APRS_SERVER_HOST, settings.APRS_SERVER_PORT)) - login = 'user %s pass %s vers ogn-gateway-python %s %s\n' % (aprs_user, settings.APRS_PASSCODE, MODULE_VERSION, settings.APRS_FILTER) + login = create_aprs_login(aprs_user, -1, settings.APRS_APP_NAME, settings.APRS_APP_VER, settings.APRS_FILTER) self.sock.send(login.encode()) self.sock_file = self.sock.makefile('rw') diff --git a/ogn/gateway/settings.py b/ogn/gateway/settings.py index 3216638..d311da2 100644 --- a/ogn/gateway/settings.py +++ b/ogn/gateway/settings.py @@ -1,7 +1,7 @@ APRS_SERVER_HOST = 'aprs.glidernet.org' APRS_SERVER_PORT = 14580 -APRS_USER = 'PyGrabber' -APRS_PASSCODE = -1 # Read only +APRS_APP_NAME = 'ogn-gateway-python' +APRS_APP_VER = '0.2' -APRS_FILTER = "filter r/+50.0000/+10.0000/5000" +APRS_FILTER = 'r/50.0000/10.0000/5000' APRS_KEEPALIVE_TIME = 240 diff --git a/tests/test_aprs_utils.py b/tests/test_aprs_utils.py index 5f8f0dd..351d976 100644 --- a/tests/test_aprs_utils.py +++ b/tests/test_aprs_utils.py @@ -1,7 +1,7 @@ import unittest from datetime import datetime -from ogn.aprs_utils import dmsToDeg, createTimestamp +from ogn.aprs_utils import dmsToDeg, createTimestamp, create_aprs_login class TestStringMethods(unittest.TestCase): @@ -21,5 +21,13 @@ class TestStringMethods(unittest.TestCase): with self.assertRaises(Exception): createTimestamp(datetime(2015, 10, 15, 23, 59, 59), '123456') + def test_create_aprs_login(self): + basic_login = create_aprs_login('klaus', -1, 'myApp', '0.1') + self.assertEqual('user klaus pass -1 vers myApp 0.1\n', basic_login) + + login_with_filter = create_aprs_login('klaus', -1, 'myApp', '0.1', 'r/48.0/11.0/100') + self.assertEqual('user klaus pass -1 vers myApp 0.1 filter r/48.0/11.0/100\n', login_with_filter) + + if __name__ == '__main__': unittest.main()