211 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| """
 | |
| Script de monitoring pour le scraper agenda du libre
 | |
| Affiche les statistiques et l'état du scraper
 | |
| """
 | |
| 
 | |
| import json
 | |
| import os
 | |
| import sys
 | |
| from datetime import datetime, timedelta
 | |
| from typing import Dict, Any
 | |
| 
 | |
| class AgendaDuLibreMonitor:
 | |
|     def __init__(self, data_file: str = "agendadulibre_events.json"):
 | |
|         self.data_file = data_file
 | |
|         self.events_data = self.load_events_data()
 | |
|     
 | |
|     def load_events_data(self) -> Dict[str, Any]:
 | |
|         """Charge les données d'événements"""
 | |
|         if os.path.exists(self.data_file):
 | |
|             try:
 | |
|                 with open(self.data_file, 'r', encoding='utf-8') as f:
 | |
|                     return json.load(f)
 | |
|             except Exception as e:
 | |
|                 print(f"❌ Erreur lors du chargement de {self.data_file}: {e}")
 | |
|                 return {"events": {}, "last_update": None}
 | |
|         return {"events": {}, "last_update": None}
 | |
|     
 | |
|     def get_statistics(self) -> Dict[str, Any]:
 | |
|         """Calcule les statistiques des événements"""
 | |
|         events = self.events_data.get("events", {})
 | |
|         
 | |
|         stats = {
 | |
|             "total_events": len(events),
 | |
|             "saved": 0,
 | |
|             "already_exists": 0,
 | |
|             "error": 0,
 | |
|             "unknown": 0,
 | |
|             "recent_errors": 0,
 | |
|             "last_update": self.events_data.get("last_update"),
 | |
|             "events_by_status": {},
 | |
|             "recent_events": []
 | |
|         }
 | |
|         
 | |
|         # Analyser les statuts
 | |
|         for event_id, event_data in events.items():
 | |
|             status = event_data.get("status", "unknown")
 | |
|             stats["events_by_status"][status] = stats["events_by_status"].get(status, 0) + 1
 | |
|             
 | |
|             if status == "saved":
 | |
|                 stats["saved"] += 1
 | |
|             elif status == "already_exists":
 | |
|                 stats["already_exists"] += 1
 | |
|             elif status == "error":
 | |
|                 stats["error"] += 1
 | |
|             else:
 | |
|                 stats["unknown"] += 1
 | |
|             
 | |
|             # Vérifier les erreurs récentes (dernières 24h)
 | |
|             last_attempt = event_data.get("last_attempt")
 | |
|             if last_attempt and status == "error":
 | |
|                 try:
 | |
|                     attempt_time = datetime.fromisoformat(last_attempt.replace('Z', '+00:00'))
 | |
|                     if datetime.now() - attempt_time.replace(tzinfo=None) < timedelta(hours=24):
 | |
|                         stats["recent_errors"] += 1
 | |
|                 except:
 | |
|                     pass
 | |
|             
 | |
|             # Collecter les événements récents (derniers 10)
 | |
|             if len(stats["recent_events"]) < 10:
 | |
|                 event_info = {
 | |
|                     "id": event_id,
 | |
|                     "label": event_data.get("event", {}).get("properties", {}).get("label", "Sans titre"),
 | |
|                     "status": status,
 | |
|                     "last_attempt": last_attempt,
 | |
|                     "message": event_data.get("message", "")
 | |
|                 }
 | |
|                 stats["recent_events"].append(event_info)
 | |
|         
 | |
|         return stats
 | |
|     
 | |
|     def display_statistics(self):
 | |
|         """Affiche les statistiques de manière formatée"""
 | |
|         stats = self.get_statistics()
 | |
|         
 | |
|         print("📊 Statistiques du scraper agenda du libre")
 | |
|         print("=" * 50)
 | |
|         
 | |
|         # Informations générales
 | |
|         print(f"📁 Fichier de données: {self.data_file}")
 | |
|         print(f"📅 Dernière mise à jour: {stats['last_update'] or 'Jamais'}")
 | |
|         print(f"📈 Total d'événements traités: {stats['total_events']}")
 | |
|         print()
 | |
|         
 | |
|         # Répartition par statut
 | |
|         print("📋 Répartition par statut:")
 | |
|         for status, count in stats["events_by_status"].items():
 | |
|             emoji = {
 | |
|                 "saved": "✅",
 | |
|                 "already_exists": "⚠️",
 | |
|                 "error": "❌",
 | |
|                 "unknown": "❓"
 | |
|             }.get(status, "❓")
 | |
|             print(f"   {emoji} {status}: {count}")
 | |
|         print()
 | |
|         
 | |
|         # Erreurs récentes
 | |
|         if stats["recent_errors"] > 0:
 | |
|             print(f"🚨 Erreurs récentes (24h): {stats['recent_errors']}")
 | |
|             print()
 | |
|         
 | |
|         # Événements récents
 | |
|         if stats["recent_events"]:
 | |
|             print("🕒 Événements récents:")
 | |
|             for event in stats["recent_events"][:5]:
 | |
|                 emoji = {
 | |
|                     "saved": "✅",
 | |
|                     "already_exists": "⚠️",
 | |
|                     "error": "❌",
 | |
|                     "unknown": "❓"
 | |
|                 }.get(event["status"], "❓")
 | |
|                 
 | |
|                 print(f"   {emoji} {event['label'][:50]}{'...' if len(event['label']) > 50 else ''}")
 | |
|                 if event["status"] == "error":
 | |
|                     print(f"      💬 {event['message']}")
 | |
|             print()
 | |
|         
 | |
|         # Recommandations
 | |
|         self.display_recommendations(stats)
 | |
|     
 | |
|     def display_recommendations(self, stats: Dict[str, Any]):
 | |
|         """Affiche des recommandations basées sur les statistiques"""
 | |
|         print("💡 Recommandations:")
 | |
|         
 | |
|         if stats["total_events"] == 0:
 | |
|             print("   - Aucun événement traité. Exécutez le scraper pour commencer.")
 | |
|         elif stats["error"] > stats["saved"]:
 | |
|             print("   - Beaucoup d'erreurs détectées. Vérifiez la connectivité API.")
 | |
|         elif stats["recent_errors"] > 5:
 | |
|             print("   - Erreurs récentes nombreuses. Vérifiez les logs.")
 | |
|         elif stats["saved"] > 0:
 | |
|             print("   - Scraper fonctionne correctement.")
 | |
|         
 | |
|         if stats["already_exists"] > stats["saved"]:
 | |
|             print("   - Beaucoup d'événements déjà existants. Le système de déduplication fonctionne.")
 | |
|         
 | |
|         print()
 | |
|     
 | |
|     def check_file_status(self):
 | |
|         """Vérifie l'état du fichier de données"""
 | |
|         if not os.path.exists(self.data_file):
 | |
|             print(f"❌ Fichier de données non trouvé: {self.data_file}")
 | |
|             return False
 | |
|         
 | |
|         try:
 | |
|             stat = os.stat(self.data_file)
 | |
|             size = stat.st_size
 | |
|             mtime = datetime.fromtimestamp(stat.st_mtime)
 | |
|             
 | |
|             print(f"📁 État du fichier de données:")
 | |
|             print(f"   - Taille: {size:,} octets")
 | |
|             print(f"   - Dernière modification: {mtime}")
 | |
|             print(f"   - Lisible: {'✅' if os.access(self.data_file, os.R_OK) else '❌'}")
 | |
|             print(f"   - Écriture: {'✅' if os.access(self.data_file, os.W_OK) else '❌'}")
 | |
|             print()
 | |
|             
 | |
|             return True
 | |
|         except Exception as e:
 | |
|             print(f"❌ Erreur lors de la vérification du fichier: {e}")
 | |
|             return False
 | |
|     
 | |
|     def show_help(self):
 | |
|         """Affiche l'aide"""
 | |
|         print("🔍 Monitor agenda du libre - Aide")
 | |
|         print("=" * 40)
 | |
|         print("Usage: python3 monitor_agendadulibre.py [options]")
 | |
|         print()
 | |
|         print("Options:")
 | |
|         print("  --stats, -s     Afficher les statistiques (défaut)")
 | |
|         print("  --file, -f      Vérifier l'état du fichier")
 | |
|         print("  --help, -h      Afficher cette aide")
 | |
|         print()
 | |
|         print("Exemples:")
 | |
|         print("  python3 monitor_agendadulibre.py")
 | |
|         print("  python3 monitor_agendadulibre.py --file")
 | |
|         print("  python3 monitor_agendadulibre.py --stats")
 | |
| 
 | |
| def main():
 | |
|     """Fonction principale"""
 | |
|     import argparse
 | |
|     
 | |
|     parser = argparse.ArgumentParser(description="Monitor pour le scraper agenda du libre")
 | |
|     parser.add_argument("--stats", "-s", action="store_true", default=True,
 | |
|                        help="Afficher les statistiques")
 | |
|     parser.add_argument("--file", "-f", action="store_true",
 | |
|                        help="Vérifier l'état du fichier de données")
 | |
|     parser.add_argument("--data-file", default="agendadulibre_events.json",
 | |
|                        help="Fichier de données à analyser")
 | |
|     
 | |
|     args = parser.parse_args()
 | |
|     
 | |
|     monitor = AgendaDuLibreMonitor(args.data_file)
 | |
|     
 | |
|     if args.file:
 | |
|         monitor.check_file_status()
 | |
|     
 | |
|     if args.stats:
 | |
|         monitor.display_statistics()
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 | 
