|
|
|
@ -21,6 +21,7 @@ from dotenv import load_dotenv |
|
|
|
|
|
|
|
|
|
|
|
load_dotenv() |
|
|
|
load_dotenv() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Define constants |
|
|
|
REFERENCE_DATE_FILE = ENGAGEMENT_REFERENCE_DATE_FILE |
|
|
|
REFERENCE_DATE_FILE = ENGAGEMENT_REFERENCE_DATE_FILE |
|
|
|
LOCK_FILE = "/home/shane/foodie_automator/locks/foodie_engagement_tweet.lock" |
|
|
|
LOCK_FILE = "/home/shane/foodie_automator/locks/foodie_engagement_tweet.lock" |
|
|
|
LOG_FILE = "/home/shane/foodie_automator/logs/foodie_engagement_tweet.log" |
|
|
|
LOG_FILE = "/home/shane/foodie_automator/logs/foodie_engagement_tweet.log" |
|
|
|
@ -31,64 +32,59 @@ URL = "https://insiderfoodie.com" |
|
|
|
URL_SHORTENED_LENGTH = 23 # Twitter's shortened URL length |
|
|
|
URL_SHORTENED_LENGTH = 23 # Twitter's shortened URL length |
|
|
|
CURRENT_YEAR = "2025" # Explicitly set the current year for the prompt |
|
|
|
CURRENT_YEAR = "2025" # Explicitly set the current year for the prompt |
|
|
|
|
|
|
|
|
|
|
|
def setup_logging(): |
|
|
|
# Setup logging at the very start |
|
|
|
"""Initialize logging with pruning of old logs.""" |
|
|
|
logger = logging.getLogger() |
|
|
|
try: |
|
|
|
logger.setLevel(logging.DEBUG) |
|
|
|
# Ensure the logs directory exists |
|
|
|
|
|
|
|
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True) |
|
|
|
# Clear any existing handlers (in case another script configured the logger) |
|
|
|
|
|
|
|
logger.handlers = [] |
|
|
|
# Configure logging first |
|
|
|
|
|
|
|
logging.basicConfig( |
|
|
|
# Console handler |
|
|
|
filename=LOG_FILE, |
|
|
|
console_handler = logging.StreamHandler() |
|
|
|
level=logging.DEBUG, |
|
|
|
console_handler.setLevel(logging.DEBUG) |
|
|
|
format='%(asctime)s - %(levelname)s - %(message)s', |
|
|
|
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')) |
|
|
|
datefmt='%Y-%m-%d %H:%M:%S' |
|
|
|
logger.addHandler(console_handler) |
|
|
|
) |
|
|
|
|
|
|
|
console_handler = logging.StreamHandler() |
|
|
|
# File handler |
|
|
|
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) |
|
|
|
try: |
|
|
|
console_handler.setLevel(logging.DEBUG) # Show DEBUG messages in console too |
|
|
|
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True) |
|
|
|
logging.getLogger().addHandler(console_handler) |
|
|
|
file_handler = logging.FileHandler(LOG_FILE, mode='a') |
|
|
|
logging.getLogger("openai").setLevel(logging.WARNING) |
|
|
|
file_handler.setLevel(logging.DEBUG) |
|
|
|
logging.getLogger("tweepy").setLevel(logging.WARNING) |
|
|
|
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')) |
|
|
|
|
|
|
|
logger.addHandler(file_handler) |
|
|
|
# Now that logging is configured, prune old logs if the file exists |
|
|
|
logging.info("File logging initialized successfully.") |
|
|
|
if os.path.exists(LOG_FILE): |
|
|
|
except Exception as e: |
|
|
|
with open(LOG_FILE, 'r') as f: |
|
|
|
logging.error(f"Failed to setup file logging to {LOG_FILE}: {e}. Continuing with console-only logging.") |
|
|
|
lines = f.readlines() |
|
|
|
|
|
|
|
cutoff = datetime.now(timezone.utc) - timedelta(days=LOG_PRUNE_DAYS) |
|
|
|
# Prune old logs if the file exists |
|
|
|
pruned_lines = [] |
|
|
|
try: |
|
|
|
malformed_count = 0 |
|
|
|
if os.path.exists(LOG_FILE): |
|
|
|
for line in lines: |
|
|
|
with open(LOG_FILE, 'r') as f: |
|
|
|
if len(line) < 19 or not line[:19].replace('-', '').replace(':', '').replace(' ', '').isdigit(): |
|
|
|
lines = f.readlines() |
|
|
|
malformed_count += 1 |
|
|
|
cutoff = datetime.now(timezone.utc) - timedelta(days=LOG_PRUNE_DAYS) |
|
|
|
continue |
|
|
|
pruned_lines = [] |
|
|
|
try: |
|
|
|
malformed_count = 0 |
|
|
|
timestamp = datetime.strptime(line[:19], '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc) |
|
|
|
for line in lines: |
|
|
|
if timestamp > cutoff: |
|
|
|
if len(line) < 19 or not line[:19].replace('-', '').replace(':', '').replace(' ', '').isdigit(): |
|
|
|
pruned_lines.append(line) |
|
|
|
malformed_count += 1 |
|
|
|
except ValueError: |
|
|
|
continue |
|
|
|
malformed_count += 1 |
|
|
|
try: |
|
|
|
continue |
|
|
|
timestamp = datetime.strptime(line[:19], '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc) |
|
|
|
if malformed_count > 0: |
|
|
|
if timestamp > cutoff: |
|
|
|
logging.info(f"Skipped {malformed_count} malformed log lines during pruning") |
|
|
|
pruned_lines.append(line) |
|
|
|
with open(LOG_FILE, 'w') as f: |
|
|
|
except ValueError: |
|
|
|
f.writelines(pruned_lines) |
|
|
|
malformed_count += 1 |
|
|
|
|
|
|
|
continue |
|
|
|
logging.info("Logging initialized for foodie_engagement_tweet.py") |
|
|
|
if malformed_count > 0: |
|
|
|
except Exception as e: |
|
|
|
logging.info(f"Skipped {malformed_count} malformed log lines during pruning") |
|
|
|
# Fallback to console-only logging if file logging fails |
|
|
|
with open(LOG_FILE, 'w') as f: |
|
|
|
logging.basicConfig( |
|
|
|
f.writelines(pruned_lines) |
|
|
|
level=logging.DEBUG, |
|
|
|
except Exception as e: |
|
|
|
format='%(asctime)s - %(levelname)s - %(message)s', |
|
|
|
logging.warning(f"Failed to prune log file {LOG_FILE}: {e}") |
|
|
|
datefmt='%Y-%m-%d %H:%M:%S' |
|
|
|
|
|
|
|
) |
|
|
|
logging.info("Logging initialized for foodie_engagement_tweet.py") |
|
|
|
console_handler = logging.StreamHandler() |
|
|
|
logging.getLogger("openai").setLevel(logging.WARNING) |
|
|
|
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) |
|
|
|
logging.getLogger("tweepy").setLevel(logging.WARNING) |
|
|
|
console_handler.setLevel(logging.DEBUG) |
|
|
|
|
|
|
|
logging.getLogger().addHandler(console_handler) |
|
|
|
|
|
|
|
logging.getLogger("openai").setLevel(logging.WARNING) |
|
|
|
|
|
|
|
logging.getLogger("tweepy").setLevel(logging.WARNING) |
|
|
|
|
|
|
|
logging.error(f"Failed to setup file logging to {LOG_FILE}: {e}. Falling back to console-only logging.") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def acquire_lock(): |
|
|
|
def acquire_lock(): |
|
|
|
"""Acquire a lock to prevent concurrent runs.""" |
|
|
|
"""Acquire a lock to prevent concurrent runs.""" |
|
|
|
@ -434,7 +430,6 @@ def main(): |
|
|
|
lock_fd = None |
|
|
|
lock_fd = None |
|
|
|
try: |
|
|
|
try: |
|
|
|
lock_fd = acquire_lock() |
|
|
|
lock_fd = acquire_lock() |
|
|
|
setup_logging() |
|
|
|
|
|
|
|
post_engagement_tweet() |
|
|
|
post_engagement_tweet() |
|
|
|
except Exception as e: |
|
|
|
except Exception as e: |
|
|
|
logging.error(f"Fatal error in main: {e}", exc_info=True) |
|
|
|
logging.error(f"Fatal error in main: {e}", exc_info=True) |
|
|
|
|