A bundled prometheus plugin, on by default like the other protocol plugins. Targets are rows edited on its page: address, bearer token (encrypted), interval, keep/leave-out name patterns and a series cap. Steward does the filtering; the endpoint serves everything (Archives' ruling). - A 5 s tick scrapes due targets at once, each within a 30 s deadline, and writes the outcome to its row and its series through record_metrics, so alert rules can watch any of them. - Gauges are stored as they are; counters (and a histogram's or summary's _sum/_count) as <name>_per_sec rates from the second scrape. Buckets and quantiles are skipped. A labelled series is stored under "<target>:k=v,…". Each target also records is_up, scrape_ms, series_kept and series_capped. - Pages: targets not answering first, with why; a target's series grouped by metric with their newest values; a chart per series; the editor with Test, which scrapes once and says what would be stored. - The counter-to-rate keeper moves to steward/core/counter_rates.py; SNMP's RateKeeper now scales its rate on top of it. - metric_value reads Prometheus's _seconds as a span and _per_sec as a rate. - The catalog guard treats an empty list as a dynamic source (snmp, prometheus), as the rule form does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# plugins/prometheus/models.py
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import JSON, Boolean, DateTime, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from steward.core.ids import time_ordered_id
|
||||
from steward.models.base import Base
|
||||
|
||||
|
||||
class PrometheusTarget(Base):
|
||||
"""A /metrics endpoint Steward scrapes, edited on the Prometheus page.
|
||||
|
||||
The bearer token is stored encrypted. keep and drop are lists of name
|
||||
patterns ("fabledarchives_*") an admin chooses: Steward does the
|
||||
filtering, the endpoint serves everything. The last_* columns are the
|
||||
newest scrape's outcome, written by the scraper, so a page can say why a
|
||||
target isn't answering without asking it.
|
||||
"""
|
||||
__tablename__ = "prometheus_targets"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=time_ordered_id)
|
||||
name: Mapped[str] = mapped_column(String(100), nullable=False, unique=True)
|
||||
url: Mapped[str] = mapped_column(String(500), nullable=False)
|
||||
token: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
verify_tls: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
interval_seconds: Mapped[int] = mapped_column(Integer, nullable=False, default=60)
|
||||
keep: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
||||
drop: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
||||
series_cap: Mapped[int] = mapped_column(Integer, nullable=False, default=1000)
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc))
|
||||
last_scraped_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
last_ok_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
last_error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
last_kept: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
last_dropped: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
last_capped: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
Reference in New Issue
Block a user