Really-amin commited on
Commit
7fc7d37
·
verified ·
1 Parent(s): c2d193a

Upload db_manager.py

Browse files
Files changed (1) hide show
  1. database/db_manager.py +123 -0
database/db_manager.py CHANGED
@@ -1537,3 +1537,126 @@ if __name__ == "__main__":
1537
  if table != 'database_size_mb':
1538
  print(f" {table}: {count}")
1539
  print(f" Database Size: {stats.get('database_size_mb', 0)} MB")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1537
  if table != 'database_size_mb':
1538
  print(f" {table}: {count}")
1539
  print(f" Database Size: {stats.get('database_size_mb', 0)} MB")
1540
+
1541
+
1542
+ # === Monkey-patch compatibility methods for legacy health logging ===
1543
+ # These provide the same interface as the older `Database` class from database.py
1544
+ # so that calls like `db.log_provider_status` and `db.get_uptime_percentage`
1545
+ # used in app.py continue to work when using DatabaseManager with SQLAlchemy.
1546
+
1547
+ from sqlalchemy import text as _sa_text
1548
+ from datetime import datetime as _dt, timedelta as _td
1549
+
1550
+ def _dm_log_provider_status(
1551
+ self,
1552
+ provider_name: str,
1553
+ category: str,
1554
+ status: str,
1555
+ response_time: Optional[float] = None,
1556
+ status_code: Optional[int] = None,
1557
+ endpoint_tested: Optional[str] = None,
1558
+ error_message: Optional[str] = None,
1559
+ ):
1560
+ """Log provider status into a simple `status_log` table.
1561
+
1562
+ This mirrors the behavior of the older sqlite-based `Database.log_provider_status`
1563
+ implementation so that existing code paths in app.py keep working.
1564
+ """
1565
+ try:
1566
+ # Ensure table exists (idempotent)
1567
+ create_sql = _sa_text("""
1568
+ CREATE TABLE IF NOT EXISTS status_log (
1569
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1570
+ provider_name TEXT NOT NULL,
1571
+ category TEXT NOT NULL,
1572
+ status TEXT NOT NULL,
1573
+ response_time REAL,
1574
+ status_code INTEGER,
1575
+ error_message TEXT,
1576
+ endpoint_tested TEXT,
1577
+ timestamp REAL NOT NULL,
1578
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
1579
+ )
1580
+ """)
1581
+ insert_sql = _sa_text("""
1582
+ INSERT INTO status_log
1583
+ (provider_name, category, status, response_time, status_code,
1584
+ error_message, endpoint_tested, timestamp)
1585
+ VALUES (:provider_name, :category, :status, :response_time, :status_code,
1586
+ :error_message, :endpoint_tested, :timestamp)
1587
+ """)
1588
+ with self.engine.begin() as conn:
1589
+ conn.execute(create_sql)
1590
+ conn.execute(
1591
+ insert_sql,
1592
+ {
1593
+ "provider_name": provider_name,
1594
+ "category": category,
1595
+ "status": status,
1596
+ "response_time": response_time,
1597
+ "status_code": status_code,
1598
+ "error_message": error_message,
1599
+ "endpoint_tested": endpoint_tested,
1600
+ "timestamp": _dt.now().timestamp(),
1601
+ },
1602
+ )
1603
+ except Exception as e: # pragma: no cover - logging safeguard
1604
+ logger.error(f"Failed to log provider status for {provider_name}: {e}", exc_info=True)
1605
+
1606
+
1607
+ def _dm_get_uptime_percentage(
1608
+ self,
1609
+ provider_name: str,
1610
+ hours: int = 24,
1611
+ ) -> float:
1612
+ """Calculate uptime percentage from `status_log` table.
1613
+
1614
+ This approximates the legacy behavior:
1615
+ uptime = (online_rows / total_rows) * 100
1616
+ where `status = 'online'` is treated as healthy.
1617
+ """
1618
+ try:
1619
+ cutoff = _dt.now() - _td(hours=hours)
1620
+ # Ensure table exists before querying
1621
+ create_sql = _sa_text("""
1622
+ CREATE TABLE IF NOT EXISTS status_log (
1623
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1624
+ provider_name TEXT NOT NULL,
1625
+ category TEXT NOT NULL,
1626
+ status TEXT NOT NULL,
1627
+ response_time REAL,
1628
+ status_code INTEGER,
1629
+ error_message TEXT,
1630
+ endpoint_tested TEXT,
1631
+ timestamp REAL NOT NULL,
1632
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
1633
+ )
1634
+ """)
1635
+ query_sql = _sa_text("""
1636
+ SELECT
1637
+ COUNT(*) AS total,
1638
+ SUM(CASE WHEN status = 'online' THEN 1 ELSE 0 END) AS online
1639
+ FROM status_log
1640
+ WHERE provider_name = :provider_name
1641
+ AND created_at >= :cutoff
1642
+ """)
1643
+ with self.engine.begin() as conn:
1644
+ conn.execute(create_sql)
1645
+ result = conn.execute(
1646
+ query_sql,
1647
+ {"provider_name": provider_name, "cutoff": cutoff},
1648
+ ).first()
1649
+ if result and result[0]:
1650
+ total = result[0] or 0
1651
+ online = result[1] or 0
1652
+ if total > 0:
1653
+ return round((online / total) * 100.0, 2)
1654
+ return 0.0
1655
+ except Exception as e: # pragma: no cover - logging safeguard
1656
+ logger.error(f"Failed to compute uptime for {provider_name}: {e}", exc_info=True)
1657
+ return 0.0
1658
+
1659
+
1660
+ # Attach methods to DatabaseManager so existing code can call them.
1661
+ DatabaseManager.log_provider_status = _dm_log_provider_status # type: ignore[attr-defined]
1662
+ DatabaseManager.get_uptime_percentage = _dm_get_uptime_percentage # type: ignore[attr-defined]