feat: add logging to control output based on TTY context

- Replaced print() with logging.info() and logging.error()
- Added logging configuration to output INFO messages only in TTY
- Ensured ERROR messages are always logged to stdout, including cron runs
- Used sys.stdout.isatty() to detect terminal context
- Maintained existing functionality with updated config and SMTP setup
This commit is contained in:
Edward Betts 2025-02-21 17:00:44 -05:00
parent 9f0b2c843f
commit 7f7cbfe65e

View file

@ -2,7 +2,9 @@
import configparser import configparser
import json import json
import logging
import smtplib import smtplib
import sys
from datetime import date from datetime import date
from email.mime.text import MIMEText from email.mime.text import MIMEText
from pathlib import Path from pathlib import Path
@ -33,6 +35,22 @@ DATA_DIR = Path.home() / "lib" / "data"
DATA_FILE = DATA_DIR / "ferrocarril_dates.json" DATA_FILE = DATA_DIR / "ferrocarril_dates.json"
URL = "https://ferrocarrilcentral.com.pe/appfcca/" URL = "https://ferrocarrilcentral.com.pe/appfcca/"
# Configure logging
logger = logging.getLogger("FerrocarrilMonitor")
logger.setLevel(logging.INFO)
# Handler for stdout
handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter("%(levelname)s: %(message)s")
handler.setFormatter(formatter)
# Only log INFO when in TTY, always log ERROR
if sys.stdout.isatty():
logger.addHandler(handler)
else:
handler.setLevel(logging.ERROR)
logger.addHandler(handler)
def parse_dates(html_content: str) -> list[date]: def parse_dates(html_content: str) -> list[date]:
doc = lxml.html.fromstring(html_content) doc = lxml.html.fromstring(html_content)
@ -57,7 +75,7 @@ def parse_dates(html_content: str) -> list[date]:
dates.append(date(year, month, day)) dates.append(date(year, month, day))
except (IndexError, ValueError) as e: except (IndexError, ValueError) as e:
print(f"Error parsing date: {e}") logger.error(f"Error parsing date: {e}")
continue continue
return dates return dates
@ -87,7 +105,7 @@ def load_config() -> configparser.ConfigParser:
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read(CONFIG_FILE) config.read(CONFIG_FILE)
if "mail" not in config: if "mail" not in config:
raise ValueError(f"Config file {CONFIG_FILE} must have an [email] section") raise ValueError(f"Config file {CONFIG_FILE} must have an [mail] section")
return config return config
@ -105,9 +123,10 @@ def send_email(new_dates: list[date], config: configparser.ConfigParser) -> None
try: try:
with smtplib.SMTP(email_config["smtp_host"]) as server: with smtplib.SMTP(email_config["smtp_host"]) as server:
server.send_message(msg) server.send_message(msg)
print("Email sent successfully") logger.info("Email sent successfully")
except Exception as e: except Exception as e:
print(f"Failed to send email: {e}") logger.error(f"Failed to send email: {e}")
raise # Re-raise to prevent saving dates if email fails
def main() -> None: def main() -> None:
@ -121,13 +140,13 @@ def main() -> None:
response.raise_for_status() response.raise_for_status()
html_content = response.text html_content = response.text
except requests.RequestException as e: except requests.RequestException as e:
print(f"Failed to fetch webpage: {e}") logger.error(f"Failed to fetch webpage: {e}")
return return
# Parse current dates # Parse current dates
current_dates = set(parse_dates(html_content)) current_dates = set(parse_dates(html_content))
if not current_dates: if not current_dates:
print("No dates found on webpage") logger.info("No dates found on webpage")
return return
# Load previous dates # Load previous dates
@ -137,7 +156,7 @@ def main() -> None:
new_dates = [d for d in current_dates if d.isoformat() not in previous_dates] new_dates = [d for d in current_dates if d.isoformat() not in previous_dates]
if new_dates: if new_dates:
print(f"New dates found: {new_dates}") logger.info(f"New dates found: {new_dates}")
try: try:
config = load_config() config = load_config()
send_email(new_dates, config) send_email(new_dates, config)
@ -145,11 +164,11 @@ def main() -> None:
list(current_dates) list(current_dates)
) # Update stored dates only if email succeeds ) # Update stored dates only if email succeeds
except FileNotFoundError as e: except FileNotFoundError as e:
print(e) logger.error(str(e))
except Exception as e: except Exception as e:
print(f"Error in processing: {e}") logger.error(f"Error in processing: {e}")
else: else:
print("No new dates found") logger.info("No new dates found")
if __name__ == "__main__": if __name__ == "__main__":