Initial commit: LogHive centralized log management system
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
"""Celery application for async background tasks."""
|
||||
|
||||
from celery import Celery
|
||||
|
||||
from app.config import settings
|
||||
|
||||
celery_app = Celery(
|
||||
"loghive",
|
||||
broker=settings.CELERY_BROKER_URL,
|
||||
backend=settings.CELERY_RESULT_BACKEND,
|
||||
include=["celery_worker.tasks"],
|
||||
)
|
||||
|
||||
celery_app.conf.update(
|
||||
task_serializer="json",
|
||||
accept_content=["json"],
|
||||
result_serializer="json",
|
||||
timezone="UTC",
|
||||
enable_utc=True,
|
||||
task_track_started=True,
|
||||
task_acks_late=True,
|
||||
worker_prefetch_multiplier=1,
|
||||
beat_schedule={
|
||||
"evaluate-alert-rules": {
|
||||
"task": "celery_worker.tasks.evaluate_alerts",
|
||||
"schedule": settings.ALERT_CHECK_INTERVAL_SECONDS,
|
||||
},
|
||||
"cleanup-old-log-indices": {
|
||||
"task": "celery_worker.tasks.cleanup_old_indices",
|
||||
"schedule": 3600, # once per hour
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Celery tasks for periodic and async processing."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
from sqlalchemy import delete
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
|
||||
|
||||
from app.config import settings
|
||||
from app.models.log import LogEntry
|
||||
from app.services.alert_service import AlertService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from celery_worker.celery_app import celery_app
|
||||
|
||||
|
||||
@celery_app.task(bind=True, max_retries=3)
|
||||
def evaluate_alerts(self):
|
||||
"""Evaluate all alert rules and trigger notifications.
|
||||
|
||||
Runs periodically (default: every 60 seconds via beat schedule).
|
||||
"""
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
if loop.is_closed():
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
result = loop.run_until_complete(_async_evaluate_alerts())
|
||||
logger.info("Alert evaluation complete: %d triggers", len(result))
|
||||
return {"triggered": len(result)}
|
||||
except Exception as e:
|
||||
logger.error("Alert evaluation failed: %s", e)
|
||||
raise self.retry(exc=e, countdown=30)
|
||||
|
||||
|
||||
async def _async_evaluate_alerts():
|
||||
"""Async body of alert evaluation."""
|
||||
engine = create_async_engine(settings.DATABASE_URL)
|
||||
factory = async_sessionmaker(engine, expire_on_commit=False)
|
||||
|
||||
try:
|
||||
async with factory() as db:
|
||||
service = AlertService(db)
|
||||
triggered = await service.evaluate_rules()
|
||||
await db.commit()
|
||||
return triggered
|
||||
finally:
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
@celery_app.task
|
||||
def cleanup_old_indices():
|
||||
"""Delete log entries older than the retention period."""
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
if loop.is_closed():
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
result = loop.run_until_complete(_async_cleanup())
|
||||
logger.info("Cleanup complete: %d entries deleted", result)
|
||||
return {"deleted": result}
|
||||
except Exception as e:
|
||||
logger.error("Cleanup failed: %s", e)
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
async def _async_cleanup() -> int:
|
||||
"""Delete old log entries."""
|
||||
engine = create_async_engine(settings.DATABASE_URL)
|
||||
factory = async_sessionmaker(engine, expire_on_commit=False)
|
||||
|
||||
try:
|
||||
cutoff = datetime.now(timezone.utc) - timedelta(days=settings.LOG_RETENTION_DAYS)
|
||||
async with factory() as db:
|
||||
result = await db.execute(delete(LogEntry).where(LogEntry.timestamp < cutoff))
|
||||
await db.commit()
|
||||
return result.rowcount
|
||||
finally:
|
||||
await engine.dispose()
|
||||
Reference in New Issue
Block a user