Skip to content

Commit

Permalink
feat: add query interval metric (fixes #225)
Browse files Browse the repository at this point in the history
  • Loading branch information
albertodonato committed Jan 22, 2025
1 parent 9ae1cf7 commit a5cd7b3
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 118 deletions.
3 changes: 3 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ The exporter provides a few builtin metrics which can be useful to track query e
``queries{database="db",query="q",status="[success|error|timeout]"}``:
a counter with number of executed queries, per database, query and status.

``query_interval{query="q"}``:
a gauge reporting the configured execution interval in seconds, if set, per query.

``query_latency{database="db",query="q"}``:
a histogram with query latencies, per database and query.

Expand Down
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,6 @@ skip_covered = true

[tool.coverage.run]
source = [ "query_exporter" ]
omit = [
"query_exporter/main.py",
]

[tool.mypy]
ignore_missing_imports = true
Expand Down
24 changes: 21 additions & 3 deletions query_exporter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from functools import partial
from pathlib import Path
import typing as t

from aiohttp.web import Application
import click
Expand All @@ -11,6 +12,7 @@
MetricConfig,
PrometheusExporterScript,
)
from prometheus_client.metrics import Gauge

from . import __version__
from .config import (
Expand All @@ -19,6 +21,7 @@
load_config,
)
from .loop import QueryLoop
from .metrics import QUERY_INTERVAL_METRIC_NAME


class QueryExporterScript(PrometheusExporterScript):
Expand Down Expand Up @@ -60,21 +63,26 @@ def configure(self, args: Arguments) -> None:
if args.check_only:
raise SystemExit(0)
self.create_metrics(self.config.metrics.values())
self._set_static_metrics()

async def on_application_startup(self, application: Application) -> None:
async def on_application_startup(
self, application: Application
) -> None: # pragma: nocover
query_loop = QueryLoop(self.config, self.registry, self.logger)
application["exporter"].set_metric_update_handler(
partial(self._update_handler, query_loop)
)
application["query-loop"] = query_loop
await query_loop.start()

async def on_application_shutdown(self, application: Application) -> None:
async def on_application_shutdown(
self, application: Application
) -> None: # pragma: nocover
await application["query-loop"].stop()

async def _update_handler(
self, query_loop: QueryLoop, metrics: list[MetricConfig]
) -> None:
) -> None: # pragma: nocover
"""Run queries with no specified schedule on each request."""
await query_loop.run_aperiodic_queries()
query_loop.clear_expired_series()
Expand All @@ -87,5 +95,15 @@ def _load_config(self, paths: list[Path]) -> Config:
self.logger.error("invalid config", error=str(error))
raise SystemExit(1)

def _set_static_metrics(self) -> None:
query_interval_metric = t.cast(
Gauge, self.registry.get_metric(QUERY_INTERVAL_METRIC_NAME)
)
for query in self.config.queries.values():
if query.interval:
query_interval_metric.labels(query=query.name).set(
query.interval
)


script = QueryExporterScript()
15 changes: 14 additions & 1 deletion query_exporter/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,21 @@
type="histogram",
labels=("query",),
)
# metrics reporting the query interval
QUERY_INTERVAL_METRIC_NAME = "query_interval"
_QUERY_INTERVAL_METRIC_CONFIG = MetricConfig(
name=QUERY_INTERVAL_METRIC_NAME,
description="Query execution interval",
type="gauge",
labels=("query",),
)


BUILTIN_METRICS = frozenset(
(
DB_ERRORS_METRIC_NAME,
QUERIES_METRIC_NAME,
QUERY_INTERVAL_METRIC_NAME,
QUERY_LATENCY_METRIC_NAME,
QUERY_TIMESTAMP_METRIC_NAME,
)
Expand All @@ -48,7 +59,7 @@ def get_builtin_metric_configs(
extra_labels: frozenset[str],
) -> dict[str, MetricConfig]:
"""Return configuration for builtin metrics."""
return {
metric_configs = {
metric_config.name: MetricConfig(
metric_config.name,
metric_config.description,
Expand All @@ -63,3 +74,5 @@ def get_builtin_metric_configs(
_QUERY_TIMESTAMP_METRIC_CONFIG,
)
}
metric_configs[QUERY_INTERVAL_METRIC_NAME] = _QUERY_INTERVAL_METRIC_CONFIG
return metric_configs
Loading

0 comments on commit a5cd7b3

Please sign in to comment.