Add check_application_logs
This commit is contained in:
parent
c09ad7f5c9
commit
92b2aba960
@ -23,6 +23,9 @@ class SiteSettings(BaseSettings):
|
||||
# TODO: confirm with Zhenyu
|
||||
BASE_RECONSILE_URL: str = "https://reconcile.freeleaps.mathmast.com"
|
||||
|
||||
# TODO: modify this with actual Loki URL
|
||||
BASE_LOKI_URL: str = "http://localhost:3100"
|
||||
|
||||
class Config:
|
||||
env_file = ".devbase-webapi.env"
|
||||
env_file_encoding = "utf-8"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Literal, List
|
||||
|
||||
from beanie import Document
|
||||
from bson import ObjectId
|
||||
@ -50,6 +50,27 @@ class CheckDeploymentStatusRequest(BaseModel):
|
||||
target_env: str
|
||||
user_id: str
|
||||
|
||||
class CheckApplicationLogsRequest(BaseModel):
|
||||
product_id: str
|
||||
target_env: Literal["alpha", "prod"] = "alpha"
|
||||
user_id: str = ''
|
||||
log_level: List[Literal["info", "error", "debug"]] = Field(default_factory=lambda: ["info"])
|
||||
start_time: datetime = datetime.now() - timedelta(minutes=5)
|
||||
end_time: datetime = datetime.now()
|
||||
limit: int = 1000
|
||||
|
||||
class CheckApplicationLogsResponse(BaseModel):
|
||||
product_id: str
|
||||
target_env: Literal["alpha", "prod"]
|
||||
user_id: str = ''
|
||||
log_level: List[Literal["info", "error", "debug"]]
|
||||
start_time: datetime
|
||||
end_time: datetime
|
||||
limit: int
|
||||
logs: list[str]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,8 @@ from fastapi import APIRouter, Depends
|
||||
from loguru import logger
|
||||
|
||||
from app.common.models import CodeDepotDoc
|
||||
from app.common.models.deployment.deployment import Deployment, InitDeploymentRequest
|
||||
from app.common.models.deployment.deployment import Deployment, InitDeploymentRequest, CheckDeploymentStatusRequest, \
|
||||
CheckApplicationLogsRequest, CheckApplicationLogsResponse
|
||||
from app.routes.deployment.service import DeploymentService, get_deployment_service
|
||||
|
||||
router = APIRouter(prefix="/deployment")
|
||||
@ -57,3 +58,19 @@ async def create_dummy_code_depot(
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create dummy code depot: {e}")
|
||||
raise e
|
||||
|
||||
@router.post("/checkApplicationLogs")
|
||||
async def check_application_logs(
|
||||
request: CheckApplicationLogsRequest,
|
||||
service: DeploymentService = Depends(get_deployment_service)
|
||||
) -> CheckApplicationLogsResponse:
|
||||
"""
|
||||
Check application logs for a given deployment.
|
||||
"""
|
||||
try:
|
||||
res = await service.check_application_logs(request)
|
||||
return res
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to check application logs: {e}")
|
||||
raise e
|
||||
|
||||
|
||||
@ -4,12 +4,14 @@ from datetime import datetime, timedelta
|
||||
from typing import List
|
||||
|
||||
import httpx
|
||||
import requests
|
||||
from fastapi import HTTPException, Depends
|
||||
|
||||
from app.common.config.site_settings import site_settings
|
||||
from app.common.models import Deployment
|
||||
from app.common.models.code_depot.code_depot import CodeDepotDoc, DepotStatus
|
||||
from app.common.models.deployment.deployment import InitDeploymentRequest
|
||||
from app.common.models.deployment.deployment import InitDeploymentRequest, CheckApplicationLogsRequest, \
|
||||
CheckApplicationLogsResponse
|
||||
|
||||
|
||||
class DeploymentService:
|
||||
@ -157,6 +159,53 @@ class DeploymentService:
|
||||
# raise HTTPException(status_code=response.status_code, detail=response.text)
|
||||
return True
|
||||
|
||||
async def check_application_logs(
|
||||
self,
|
||||
request: CheckApplicationLogsRequest,
|
||||
loki_url: str = site_settings.BASE_LOKI_URL,
|
||||
) -> CheckApplicationLogsResponse:
|
||||
# Convert to nanoseconds since epoch
|
||||
start_ns = int(request.start_time.timestamp() * 1e9)
|
||||
end_ns = int(request.end_time.timestamp() * 1e9)
|
||||
|
||||
# TODO: convert product_id to application name if needed
|
||||
base_query = f'{{application="{request.product_id}", environment="{request.target_env}"}}'
|
||||
log_level = '|'.join(request.log_level) if request.log_level else ''
|
||||
loki_query = f'{base_query} |~ "{log_level}"'
|
||||
|
||||
params = {
|
||||
"query": loki_query,
|
||||
"limit": request.limit,
|
||||
"start": start_ns,
|
||||
"end": end_ns,
|
||||
}
|
||||
|
||||
url = f"{loki_url}/loki/api/v1/query_range"
|
||||
response = requests.get(url, params=params)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Query failed: {response.status_code} - {response.text}")
|
||||
|
||||
data = response.json()
|
||||
streams = data.get("data", {}).get("result", [])
|
||||
|
||||
logs = []
|
||||
for stream in streams:
|
||||
for ts, log in stream.get("values", []):
|
||||
timestamp = datetime.fromtimestamp(int(ts) / 1e9)
|
||||
logs.append(f"[{timestamp}] {log.strip()}")
|
||||
|
||||
return CheckApplicationLogsResponse(
|
||||
product_id=request.product_id,
|
||||
target_env=request.target_env,
|
||||
user_id=request.user_id,
|
||||
log_level=request.log_level,
|
||||
start_time=request.start_time,
|
||||
end_time=request.end_time,
|
||||
limit=request.limit,
|
||||
logs=logs
|
||||
)
|
||||
|
||||
# TODO: dummy test code, remove later
|
||||
async def create_dummy_code_depot(
|
||||
self,
|
||||
|
||||
@ -8,3 +8,7 @@ pytest==7.1.2
|
||||
starlette==0.46.2
|
||||
uvicorn==0.34.2
|
||||
httpx==0.24.0
|
||||
pydantic-settings~=2.9.1
|
||||
pymongo~=4.12.1
|
||||
pydantic~=2.11.4
|
||||
requests~=2.32.3
|
||||
Loading…
Reference in New Issue
Block a user