Merakit-Deploy/wordpress/wordpress_deployer/deployment_logger.py

219 lines
6.6 KiB
Python

"""
Deployment logging module
Handles writing deployment logs to success/failed directories
"""
import logging
from datetime import datetime
from pathlib import Path
from typing import Optional
logger = logging.getLogger(__name__)
class DeploymentFileLogger:
"""Logs deployment results to files"""
def __init__(self, logs_dir: Path = Path("logs")):
"""
Initialize deployment file logger
Args:
logs_dir: Base directory for logs (default: logs/)
"""
self._logs_dir = logs_dir
self._success_dir = logs_dir / "success"
self._failed_dir = logs_dir / "failed"
self._logger = logging.getLogger(f"{__name__}.DeploymentFileLogger")
# Ensure directories exist
self._ensure_directories()
def _ensure_directories(self) -> None:
"""Create log directories if they don't exist"""
for directory in [self._success_dir, self._failed_dir]:
directory.mkdir(parents=True, exist_ok=True)
self._logger.debug(f"Ensured directory exists: {directory}")
def _sanitize_url(self, url: str) -> str:
"""
Sanitize URL for use in filename
Args:
url: URL to sanitize
Returns:
Sanitized URL safe for filename
"""
# Remove protocol if present
url = url.replace("https://", "").replace("http://", "")
# Replace invalid filename characters
return url.replace("/", "_").replace(":", "_")
def _generate_filename(self, status: str, url: str, timestamp: datetime) -> str:
"""
Generate log filename
Format: success_url_date.txt or failed_url_date.txt
Args:
status: 'success' or 'failed'
url: Deployment URL
timestamp: Deployment timestamp
Returns:
Filename string
"""
sanitized_url = self._sanitize_url(url)
date_str = timestamp.strftime("%Y%m%d_%H%M%S")
return f"{status}_{sanitized_url}_{date_str}.txt"
def log_success(
self,
url: str,
subdomain: str,
duration: float,
timestamp: Optional[datetime] = None
) -> Path:
"""
Log successful deployment
Args:
url: Deployment URL
subdomain: Subdomain used
duration: Deployment duration in seconds
timestamp: Deployment timestamp (default: now)
Returns:
Path to created log file
"""
if timestamp is None:
timestamp = datetime.now()
filename = self._generate_filename("success", url, timestamp)
log_file = self._success_dir / filename
log_content = self._format_success_log(
url, subdomain, duration, timestamp
)
log_file.write_text(log_content)
self._logger.info(f"✓ Success log written: {log_file}")
return log_file
def log_failure(
self,
url: str,
subdomain: str,
error: str,
timestamp: Optional[datetime] = None
) -> Path:
"""
Log failed deployment
Args:
url: Deployment URL (may be empty if failed early)
subdomain: Subdomain used (may be empty if failed early)
error: Error message
timestamp: Deployment timestamp (default: now)
Returns:
Path to created log file
"""
if timestamp is None:
timestamp = datetime.now()
# Handle case where URL is empty (failed before URL generation)
log_url = url if url else "unknown"
filename = self._generate_filename("failed", log_url, timestamp)
log_file = self._failed_dir / filename
log_content = self._format_failure_log(
url, subdomain, error, timestamp
)
log_file.write_text(log_content)
self._logger.info(f"✓ Failure log written: {log_file}")
return log_file
def _format_success_log(
self,
url: str,
subdomain: str,
duration: float,
timestamp: datetime
) -> str:
"""
Format success log content
Args:
url: Deployment URL
subdomain: Subdomain used
duration: Deployment duration in seconds
timestamp: Deployment timestamp
Returns:
Formatted log content
"""
return f"""╔══════════════════════════════════════════════╗
║ DEPLOYMENT SUCCESS LOG ║
╚══════════════════════════════════════════════╝
Timestamp: {timestamp.strftime("%Y-%m-%d %H:%M:%S")}
Status: SUCCESS
URL: https://{url}
Subdomain: {subdomain}
Duration: {duration:.2f} seconds
═══════════════════════════════════════════════
Deployment completed successfully.
All services are running and health checks passed.
"""
def _format_failure_log(
self,
url: str,
subdomain: str,
error: str,
timestamp: datetime
) -> str:
"""
Format failure log content
Args:
url: Deployment URL (may be empty)
subdomain: Subdomain used (may be empty)
error: Error message
timestamp: Deployment timestamp
Returns:
Formatted log content
"""
url_display = f"https://{url}" if url else "N/A (failed before URL generation)"
subdomain_display = subdomain if subdomain else "N/A"
return f"""╔══════════════════════════════════════════════╗
║ DEPLOYMENT FAILURE LOG ║
╚══════════════════════════════════════════════╝
Timestamp: {timestamp.strftime("%Y-%m-%d %H:%M:%S")}
Status: FAILED
URL: {url_display}
Subdomain: {subdomain_display}
═══════════════════════════════════════════════
ERROR:
{error}
═══════════════════════════════════════════════
Deployment failed. See error details above.
All changes have been rolled back.
"""