97 lines
3.1 KiB
Python
97 lines
3.1 KiB
Python
"""Prometheus metrics collectors."""
|
|
|
|
import logging
|
|
from typing import Callable
|
|
|
|
import sqlalchemy
|
|
from prometheus_client import REGISTRY, Gauge, make_asgi_app
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.orm import contains_eager
|
|
|
|
from spoolman.database import models
|
|
|
|
registry = REGISTRY
|
|
|
|
PREFIX = "spoolman"
|
|
|
|
SPOOL_PRICE = Gauge(f"{PREFIX}_spool_price_total", "Total Spool price", ["spool_id", "filament_id"])
|
|
SPOOL_INITIAL_WEIGHT = Gauge(
|
|
f"{PREFIX}_spool_initial_weight_grams",
|
|
"Spool Net weight in gram",
|
|
["spool_id", "filament_id"],
|
|
)
|
|
SPOOL_USED_WEIGHT = Gauge(f"{PREFIX}_spool_weight_used_grams", "Spool Used weight in gram", ["spool_id", "filament_id"])
|
|
FILAMENT_INFO = Gauge(
|
|
f"{PREFIX}_filament_info",
|
|
"Filament information",
|
|
["filament_id", "vendor", "name", "material", "color"],
|
|
)
|
|
FILAMENT_DENSITY = Gauge(f"{PREFIX}_filament_density", "Density of filament gram/cm3", ["filament_id"])
|
|
FILAMENT_DIAMETER = Gauge(f"{PREFIX}_filament_diameter_meters", "Diameter of filament", ["filament_id"])
|
|
FILAMENT_WEIGHT = Gauge(f"{PREFIX}_filament_weight_grams", "Net weight of filament", ["filament_id"])
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def make_metrics_app() -> Callable:
|
|
"""Start ASGI prometheus app with global registry."""
|
|
logger.info("Start metrics app")
|
|
return make_asgi_app(registry=registry)
|
|
|
|
|
|
metrics_app = make_asgi_app()
|
|
|
|
|
|
async def spool_metrics(db: AsyncSession) -> None:
|
|
"""Get metrics by Spools from DB and write to prometheus.
|
|
|
|
Args:
|
|
db: async db session
|
|
|
|
"""
|
|
stmt = sqlalchemy.select(models.Spool).where(
|
|
sqlalchemy.or_(
|
|
models.Spool.archived.is_(False),
|
|
models.Spool.archived.is_(None),
|
|
),
|
|
)
|
|
rows = await db.execute(stmt)
|
|
result = list(rows.unique().scalars().all())
|
|
for row in result:
|
|
if row.price is not None:
|
|
SPOOL_PRICE.labels(str(row.id), str(row.filament_id)).set(row.price)
|
|
if row.initial_weight is not None:
|
|
SPOOL_INITIAL_WEIGHT.labels(str(row.id), str(row.filament_id)).set(row.initial_weight)
|
|
SPOOL_USED_WEIGHT.labels(str(row.id), str(row.filament_id)).set(row.used_weight)
|
|
|
|
|
|
async def filament_metrics(db: AsyncSession) -> None:
|
|
"""Get metrics and info by Filaments from DB and write to prometheus.
|
|
|
|
Args:
|
|
db: async db session
|
|
|
|
"""
|
|
stmt = (
|
|
sqlalchemy.select(models.Filament)
|
|
.options(contains_eager(models.Filament.vendor))
|
|
.join(models.Filament.vendor, isouter=True)
|
|
)
|
|
rows = await db.execute(stmt)
|
|
result = list(rows.unique().scalars().all())
|
|
for row in result:
|
|
vendor_name = "-"
|
|
if row.vendor is not None:
|
|
vendor_name = row.vendor.name
|
|
FILAMENT_INFO.labels(
|
|
str(row.id),
|
|
vendor_name,
|
|
row.name,
|
|
row.material,
|
|
row.color_hex,
|
|
).set(1)
|
|
FILAMENT_DENSITY.labels(str(row.id)).set(row.density)
|
|
FILAMENT_DIAMETER.labels(str(row.id)).set(row.diameter / 1000)
|
|
if row.weight is not None:
|
|
FILAMENT_WEIGHT.labels(str(row.id)).set(row.weight)
|