Add support for pg_stat_statements configuration in Targets

This commit introduces a `use_pg_stat_statements` flag for targets, allowing users to enable or disable the use of `pg_stat_statements` for query insights. It includes database schema changes, backend logic, and UI updates to manage this setting in both creation and editing workflows.
This commit is contained in:
2026-02-12 13:39:57 +01:00
parent 839943d9fd
commit 712bec3fea
8 changed files with 215 additions and 15 deletions

View File

@@ -0,0 +1,26 @@
"""add target pg_stat_statements flag
Revision ID: 0003_target_pg_stat_statements_flag
Revises: 0002_alert_definitions
Create Date: 2026-02-12
"""
from alembic import op
import sqlalchemy as sa
revision = "0003_target_pg_stat_statements_flag"
down_revision = "0002_alert_definitions"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column(
"targets",
sa.Column("use_pg_stat_statements", sa.Boolean(), nullable=False, server_default=sa.text("true")),
)
def downgrade() -> None:
op.drop_column("targets", "use_pg_stat_statements")

View File

@@ -64,6 +64,7 @@ async def create_target(
username=payload.username,
encrypted_password=encrypt_secret(payload.password),
sslmode=payload.sslmode,
use_pg_stat_statements=payload.use_pg_stat_statements,
tags=payload.tags,
)
db.add(target)
@@ -188,6 +189,11 @@ async def get_activity(target_id: int, user: User = Depends(get_current_user), d
@router.get("/{target_id}/top-queries", response_model=list[QueryStatOut])
async def get_top_queries(target_id: int, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)) -> list[QueryStatOut]:
_ = user
target = await db.scalar(select(Target).where(Target.id == target_id))
if not target:
raise HTTPException(status_code=404, detail="Target not found")
if not target.use_pg_stat_statements:
return []
rows = (
await db.scalars(
select(QueryStat)

View File

@@ -27,6 +27,7 @@ class Target(Base):
username: Mapped[str] = mapped_column(String(120), nullable=False)
encrypted_password: Mapped[str] = mapped_column(Text, nullable=False)
sslmode: Mapped[str] = mapped_column(String(20), nullable=False, default="prefer")
use_pg_stat_statements: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
tags: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)

View File

@@ -9,6 +9,7 @@ class TargetBase(BaseModel):
dbname: str
username: str
sslmode: str = "prefer"
use_pg_stat_statements: bool = True
tags: dict = Field(default_factory=dict)
@@ -33,6 +34,7 @@ class TargetUpdate(BaseModel):
username: str | None = None
password: str | None = None
sslmode: str | None = None
use_pg_stat_statements: bool | None = None
tags: dict | None = None

View File

@@ -106,18 +106,19 @@ async def collect_target(target: Target) -> None:
cache_hit_ratio = stat_db["blks_hit"] / (stat_db["blks_hit"] + stat_db["blks_read"])
query_rows = []
try:
query_rows = await conn.fetch(
"""
SELECT queryid::text, calls, total_exec_time, mean_exec_time, rows, left(query, 2000) AS query_text
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20
"""
)
except Exception:
# Extension may be disabled on monitored instance.
query_rows = []
if target.use_pg_stat_statements:
try:
query_rows = await conn.fetch(
"""
SELECT queryid::text, calls, total_exec_time, mean_exec_time, rows, left(query, 2000) AS query_text
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20
"""
)
except Exception:
# Extension may be disabled on monitored instance.
query_rows = []
async with SessionLocal() as db:
await _store_metric(db, target.id, "connections_total", activity["total_connections"], {})