freelance-project-34-market.../docker/checks/rest.py
Siarhei Siniak 7f2f0cbda3 [+] update checks service
1. make metrics in commands_typed
    be agnostic of fastapi, django;
  2. implement ping wrapper for rest.py in checks;
  3. use env settings to specify hosts to ping;
  4. add pyright, ruff into Makefile;
  5. test in production;
2025-08-29 11:45:23 +03:00

96 lines
1.7 KiB
Python

import fastapi
import re
import numpy
import subprocess
import fastapi.responses
import pydantic_settings
import logging
logger = logging.getLogger(__name__)
from online.fxreader.pr34.commands_typed import metrics as pr34_metrics
from typing import Optional, Any, ClassVar
class Settings(pydantic_settings.BaseSettings):
checks_hosts: list[str]
_singleton: ClassVar[Optional['Settings']] = None
@classmethod
def singleton(cls) -> 'Settings':
if cls._singleton is None:
cls._singleton = Settings.model_validate({})
return cls._singleton
def ping_stats(host: str) -> Optional[float]:
try:
ping_output = subprocess.check_output(
[
'ping',
'-i',
'0.1',
'-c',
'3',
'-w',
'1',
host,
]
).decode('utf-8')
except:
logger.exception('')
ping_output = ''
r1 = re.compile(r'time=(\d+\.\d+)\sms')
spend_time = [float(o[1]) for o in r1.finditer(ping_output)]
if len(spend_time) == 0:
return None
else:
return float(numpy.mean(spend_time))
async def metrics_get() -> fastapi.responses.Response:
ping_res = {h: ping_stats(h) for h in Settings.singleton().checks_hosts}
metrics = [
pr34_metrics.Metric.model_validate(
dict(
name='ping_mean',
type='gauge',
help='ping to host, 3 counts, up to 1 second',
samples=[
dict(
value=str(v),
parameters=dict(
host=k,
),
)
],
)
)
for k, v in ping_res.items()
if not v is None
]
serialize_res = pr34_metrics.serialize(metrics)
return fastapi.responses.Response(
content=serialize_res.json2,
headers={
'Content-Type': serialize_res.content_type,
},
)
def get_router() -> fastapi.APIRouter:
router = fastapi.APIRouter()
router.get('/metrics')(metrics_get)
return router