From 89994c1f0a64400e4f5e33c834edc9324c62ebd1 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 15 Feb 2024 18:12:13 +0000 Subject: [PATCH] Update logging and error handling * Move from basic logging to more detailed logging with a log file. * Improve error handling in several functions. * Modify the way log messages are displayed. --- .gitignore | 1 + remindme_caldav.py | 50 ++++++++++++++++++++--------------------- remindme_caldav.service | 3 ++- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index f85787c..cf97d3c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ config_local.toml status alert_history +log __pycache__ diff --git a/remindme_caldav.py b/remindme_caldav.py index 1d309bf..eb17583 100644 --- a/remindme_caldav.py +++ b/remindme_caldav.py @@ -12,25 +12,23 @@ from pathlib import Path import argparse, textwrap, logging from alert_processor import AlertProcessor -def setup_logger(loglevel): - """Setup basic logging.""" - loglevel = getattr(logging, loglevel.upper(), None) - - if not isinstance(loglevel, int): - raise ValueError('Invalid log level: %s' % loglevel) - - logging.basicConfig(filename='app.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s') - logger = logging.getLogger() - logger.setLevel(loglevel) +#Setup basic logging. +log_format='[%(levelname)s] %(asctime)s %(message)s' +logging.basicConfig(format=log_format, level=logging.INFO) +logger = logging.getLogger() +file_handler = logging.FileHandler('log', mode='a') +formatter = logging.Formatter(log_format) +file_handler.setFormatter(formatter) +logger.addHandler(file_handler) def parse_args(): """Parse command line arguments.""" parser = argparse.ArgumentParser(description="A simple calendar alerting daemon written in Python") parser.add_argument('--config', type=str, help='Path to config file. Must be .toml') - parser.add_argument('--loglevel', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='INFO', help='Set the logging level') + parser.add_argument('--loglevel', choices=['info', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='INFO', help='Set the logging level') args = parser.parse_args() if args.config is None: - logging.error("No config file provided. Please use --config path_to_config.toml") + logger.error("No config file provided. Please use --config path_to_config.toml") sys.exit(1) return args @@ -38,14 +36,14 @@ def read_file(filename): try: return Path(filename).read_text() except FileNotFoundError as e: - logging.error("Error: The specified file does not exist.") + logger.error("Error: The specified file does not exist.") sys.exit(1) def parse_toml(content): try: return toml.loads(content) except Exception as e: - logging.error("Error: Failed to parse TOML file.") + logger.error("Error: Failed to parse TOML file.") sys.exit(1) def calculate_event_hash(event): @@ -68,44 +66,44 @@ class FileChangeHandler(FileSystemEventHandler): self.event_list = event_list def on_modified(self, event): - logging.debug(f"File modified: {event.src_path}") + logger.info(f"File modified: {event.src_path}") if not event.is_directory: try: with open(event.src_path, 'r') as f: cal_str = f.read() except Exception as e: - logging.error(f"Not a valid file: {event.src_path}. Error: {e}") + logger.error(f"Not a valid file: {event.src_path}. Error: {e}") return try: event_dict = self.calendar_parser.parse_calendar(cal_str) # Use the instance to call parse_calendar method except Exception as e: - logging.error(f"Failed to parse calendar event at: {event.src_path}. Error: {e}") + logger.error(f"Failed to parse calendar event at: {event.src_path}. Error: {e}") return self.handle_modified(old_event=None, event_dict=event_dict) def on_deleted(self, event): - logging.debug(f"File deleted: {event.src_path}") + logger.info(f"File deleted: {event.src_path}") if not event.is_directory: uid = os.path.splitext(os.path.basename(event.src_path))[0] # Get the UID from the file path without extension self.handle_modified(old_event=None, event_dict={"uid": uid}, remove=True) def on_created(self, event): - logging.debug(f"File created: {event.src_path}") + logger.info(f"File created: {event.src_path}") if not event.is_directory: try: with open(event.src_path, 'r') as f: cal_str = f.read() except Exception as e: - logging.error(f"Not a valid file: {event.src_path}. Error: {e}") + logger.error(f"Not a valid file: {event.src_path}. Error: {e}") return try: event_dict = self.calendar_parser.parse_calendar(cal_str) # Use the instance to call parse_calendar method except Exception as e: - logging.error(f"Failed to parse calendar event at: {event.src_path}. Error: {e}") + logger.error(f"Failed to parse calendar event at: {event.src_path}. Error: {e}") return self.handle_modified(old_event=None, event_dict=event_dict) @@ -118,7 +116,7 @@ class FileChangeHandler(FileSystemEventHandler): new_hash = calculate_event_hash(event_dict) if new_hash != old_hash: - logging.debug(f"Event with UID {old_event['uid']} has been modified or deleted") + logger.info(f"Event with UID {old_event['uid']} has been modified or deleted") self.event_list[i] = event_dict break else: @@ -126,7 +124,7 @@ class FileChangeHandler(FileSystemEventHandler): else: # If remove is True, remove the event from the list for i, old_event in enumerate(self.event_list): if old_event["uid"] == event_dict["uid"]: - logging.debug(f"Event with UID {old_event['uid']} has been deleted") + logger.info(f"Event with UID {old_event['uid']} has been deleted") del self.event_list[i] break @@ -336,12 +334,12 @@ def process_alert(current_time, next_alert, next_event, event, config): """ if current_time >= next_alert and current_time < next_alert + dt.timedelta(seconds=15): if len(event["alert_history"]) == 0: - logging.debug(f"First alert for '{event['summary']}' detected") + logger.info(f"First alert for '{event['summary']}' detected") event["alert_history"] = [{"timestamp_alert_triggered": current_time, "alert_defintition_time": next_alert}] elif next_alert in [i["alert_defintition_time"] for i in event["alert_history"]]: return else: - logging.debug(f"Posting alert for {event['summary']}!") + logger.info(f"Posting alert for {event['summary']}!") event["alert_history"].append({"timestamp_alert_triggered": current_time, "alert_defintition_time": next_alert}) try: processor = AlertProcessor(config) @@ -376,7 +374,7 @@ def main(): try: event_dict = calendar_parser.parse_calendar(cal_str) except Exception: - logging.error(f"Error parsing event, skipping. {file}") + logger.error(f"Error parsing event, skipping. {file}") continue event_list.append(event_dict) diff --git a/remindme_caldav.service b/remindme_caldav.service index 62395ac..1b78bce 100644 --- a/remindme_caldav.service +++ b/remindme_caldav.service @@ -8,7 +8,8 @@ Type=simple Restart=always RestartSec=1 User=root -ExecStart=/opt/remindme_caldav/.venv/bin/python3 /opt/remindme_caldav/remindme_caldav.py --config /etc/remindme_caldav/config.toml +ExecStart=/opt/remindme_caldav/.venv/bin/python3 -u /opt/remindme_caldav/remindme_caldav.py --config /etc/remindme_caldav/config.toml +Environment="PYTHONUNBUFFERED=1" [Install] WantedBy=multi-user.target