Files
orion/app/api/v1/admin/logs.py
Samir Boulahtit cc74970223 feat: add logging, marketplace, and admin enhancements
Database & Migrations:
- Add application_logs table migration for hybrid cloud logging
- Add companies table migration and restructure vendor relationships

Logging System:
- Implement hybrid logging system (database + file)
- Add log_service for centralized log management
- Create admin logs page with filtering and viewing capabilities
- Add init_log_settings.py script for log configuration
- Enhance core logging with database integration

Marketplace Integration:
- Add marketplace admin page with product management
- Create marketplace vendor page with product listings
- Implement marketplace.js for both admin and vendor interfaces
- Add marketplace integration documentation

Admin Enhancements:
- Add imports management page and functionality
- Create settings page for admin configuration
- Add vendor themes management page
- Enhance vendor detail and edit pages
- Improve code quality dashboard and violation details
- Add logs viewing and management
- Update icons guide and shared icon system

Architecture & Documentation:
- Document frontend structure and component architecture
- Document models structure and relationships
- Add vendor-in-token architecture documentation
- Add vendor RBAC (role-based access control) documentation
- Document marketplace integration patterns
- Update architecture patterns documentation

Infrastructure:
- Add platform static files structure (css, img, js)
- Move architecture_scan.py to proper models location
- Update model imports and registrations
- Enhance exception handling
- Update dependency injection patterns

UI/UX:
- Improve vendor edit interface
- Update admin user interface
- Enhance page templates documentation
- Add vendor marketplace interface
2025-12-01 21:51:07 +01:00

343 lines
10 KiB
Python

# app/api/v1/admin/logs.py
"""
Log management endpoints for admin.
Provides endpoints for:
- Viewing database logs with filters
- Reading file logs
- Log statistics
- Log settings management
- Log cleanup operations
"""
import logging
from fastapi import APIRouter, Depends, Query, Response
from sqlalchemy.orm import Session
from app.api.deps import get_current_admin_api
from app.core.database import get_db
from app.core.logging import reload_log_level
from app.services.admin_audit_service import admin_audit_service
from app.services.admin_settings_service import admin_settings_service
from app.services.log_service import log_service
from models.database.user import User
from models.schema.admin import (
ApplicationLogFilters,
ApplicationLogListResponse,
FileLogResponse,
LogSettingsResponse,
LogSettingsUpdate,
LogStatistics,
)
router = APIRouter(prefix="/logs")
logger = logging.getLogger(__name__)
# ============================================================================
# DATABASE LOGS ENDPOINTS
# ============================================================================
@router.get("/database", response_model=ApplicationLogListResponse)
def get_database_logs(
level: str | None = Query(None, description="Filter by log level"),
logger_name: str | None = Query(None, description="Filter by logger name"),
module: str | None = Query(None, description="Filter by module"),
user_id: int | None = Query(None, description="Filter by user ID"),
vendor_id: int | None = Query(None, description="Filter by vendor ID"),
search: str | None = Query(None, description="Search in message"),
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_api),
):
"""
Get logs from database with filtering.
Supports filtering by level, logger, module, user, vendor, and date range.
Returns paginated results.
"""
filters = ApplicationLogFilters(
level=level,
logger_name=logger_name,
module=module,
user_id=user_id,
vendor_id=vendor_id,
search=search,
skip=skip,
limit=limit,
)
return log_service.get_database_logs(db, filters)
@router.get("/statistics", response_model=LogStatistics)
def get_log_statistics(
days: int = Query(7, ge=1, le=90, description="Number of days to analyze"),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_api),
):
"""
Get log statistics for the last N days.
Returns counts by level, module, and recent critical errors.
"""
return log_service.get_log_statistics(db, days)
@router.delete("/database/cleanup")
def cleanup_old_logs(
retention_days: int = Query(30, ge=1, le=365),
confirm: bool = Query(False, description="Must be true to confirm cleanup"),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_api),
):
"""
Delete logs older than retention period.
Requires confirmation parameter.
"""
from fastapi import HTTPException
if not confirm:
raise HTTPException(
status_code=400,
detail="Cleanup requires confirmation parameter: confirm=true",
)
deleted_count = log_service.cleanup_old_logs(db, retention_days)
# Log action
admin_audit_service.log_action(
db=db,
admin_user_id=current_admin.id,
action="cleanup_logs",
target_type="application_logs",
target_id="bulk",
details={"retention_days": retention_days, "deleted_count": deleted_count},
)
return {
"message": f"Deleted {deleted_count} log entries older than {retention_days} days",
"deleted_count": deleted_count,
}
@router.delete("/database/{log_id}")
def delete_log(
log_id: int,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_api),
):
"""Delete a specific log entry."""
message = log_service.delete_log(db, log_id)
# Log action
admin_audit_service.log_action(
db=db,
admin_user_id=current_admin.id,
action="delete_log",
target_type="application_log",
target_id=str(log_id),
details={},
)
return {"message": message}
# ============================================================================
# FILE LOGS ENDPOINTS
# ============================================================================
@router.get("/files")
def list_log_files(
current_admin: User = Depends(get_current_admin_api),
):
"""
List all available log files.
Returns list of log files with size and modification date.
"""
return {"files": log_service.list_log_files()}
@router.get("/files/{filename}", response_model=FileLogResponse)
def get_file_log(
filename: str,
lines: int = Query(500, ge=1, le=10000, description="Number of lines to read"),
current_admin: User = Depends(get_current_admin_api),
):
"""
Read log file content.
Returns the last N lines from the specified log file.
"""
return log_service.get_file_logs(filename, lines)
@router.get("/files/{filename}/download")
def download_log_file(
filename: str,
current_admin: User = Depends(get_current_admin_api),
):
"""
Download log file.
Returns the entire log file for download.
"""
from pathlib import Path
from app.core.config import settings
from fastapi import HTTPException
from fastapi.responses import FileResponse
# Determine log file path
log_file_path = settings.log_file
if log_file_path:
log_file = Path(log_file_path).parent / filename
else:
log_file = Path("logs") / filename
if not log_file.exists():
raise HTTPException(status_code=404, detail=f"Log file '{filename}' not found")
# Log action
from app.core.database import get_db
db_gen = get_db()
db = next(db_gen)
try:
admin_audit_service.log_action(
db=db,
admin_user_id=current_admin.id,
action="download_log_file",
target_type="log_file",
target_id=filename,
details={"size_bytes": log_file.stat().st_size},
)
finally:
db.close()
return FileResponse(
log_file,
media_type="text/plain",
filename=filename,
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
# ============================================================================
# LOG SETTINGS ENDPOINTS
# ============================================================================
@router.get("/settings", response_model=LogSettingsResponse)
def get_log_settings(
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_api),
):
"""Get current log configuration settings."""
log_level = admin_settings_service.get_setting_value(db, "log_level", "INFO")
max_size_mb = admin_settings_service.get_setting_value(
db, "log_file_max_size_mb", 10
)
backup_count = admin_settings_service.get_setting_value(
db, "log_file_backup_count", 5
)
retention_days = admin_settings_service.get_setting_value(
db, "db_log_retention_days", 30
)
file_enabled = admin_settings_service.get_setting_value(
db, "file_logging_enabled", "true"
)
db_enabled = admin_settings_service.get_setting_value(
db, "db_logging_enabled", "true"
)
return LogSettingsResponse(
log_level=str(log_level),
log_file_max_size_mb=int(max_size_mb),
log_file_backup_count=int(backup_count),
db_log_retention_days=int(retention_days),
file_logging_enabled=str(file_enabled).lower() == "true",
db_logging_enabled=str(db_enabled).lower() == "true",
)
@router.put("/settings")
def update_log_settings(
settings_update: LogSettingsUpdate,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_api),
):
"""
Update log configuration settings.
Changes are applied immediately without restart (for log level).
File rotation settings require restart.
"""
from models.schema.admin import AdminSettingUpdate
updated = []
# Update log level
if settings_update.log_level:
admin_settings_service.update_setting(
db,
"log_level",
AdminSettingUpdate(value=settings_update.log_level),
current_admin.id,
)
updated.append("log_level")
# Reload log level immediately
reload_log_level()
# Update file rotation settings
if settings_update.log_file_max_size_mb:
admin_settings_service.update_setting(
db,
"log_file_max_size_mb",
AdminSettingUpdate(value=str(settings_update.log_file_max_size_mb)),
current_admin.id,
)
updated.append("log_file_max_size_mb")
if settings_update.log_file_backup_count is not None:
admin_settings_service.update_setting(
db,
"log_file_backup_count",
AdminSettingUpdate(value=str(settings_update.log_file_backup_count)),
current_admin.id,
)
updated.append("log_file_backup_count")
# Update retention
if settings_update.db_log_retention_days:
admin_settings_service.update_setting(
db,
"db_log_retention_days",
AdminSettingUpdate(value=str(settings_update.db_log_retention_days)),
current_admin.id,
)
updated.append("db_log_retention_days")
# Log action
admin_audit_service.log_action(
db=db,
admin_user_id=current_admin.id,
action="update_log_settings",
target_type="settings",
target_id="logging",
details={"updated_fields": updated},
)
return {
"message": "Log settings updated successfully",
"updated_fields": updated,
"note": "Log level changes are applied immediately. File rotation settings require restart.",
}