Write your own¶
Any object with an export(query) method is an exporter.
Use it when¶
- The data should go somewhere none of the bundled exporters reach: a database, a queue, an in-house metrics client.
- You want to act on queries as they finish, such as flagging slow ones.
Set up¶
import logging
import polars_telemetry
from polars_telemetry.model.types import Query
log = logging.getLogger("slow_queries")
class SlowQueries:
def __init__(self, threshold_ms: float) -> None:
self.threshold_ms = threshold_ms
def export(self, query: Query) -> None:
if query.wall_ms > self.threshold_ms:
log.warning("%s took %.0f ms", query.label or query.fingerprint, query.wall_ms)
polars_telemetry.install(exporter=SlowQueries(threshold_ms=500))
What you get¶
A Query per
finished query: its id, label, timings, call site, both plans by node id, the
per-node counters, fingerprint and diagnostics. The JSONL exporter's
build_profile(query) in polars_telemetry.export.profile turns one into the
profile document, if a dictionary is easier to ship.
Options¶
Whatever your exporter takes. Config(redaction=...) applies to yours too:
queries are masked before any exporter receives them, so export() never has
to. redacted(SlowQueries(500), ...) gives it a setting of its own.
Your data¶
Everything the query carries, as for the other exporters. Where it goes from there is up to you.
Cost¶
export() runs on the thread that ran the query, after it finished, so its
time is added to the caller's. Hand slow work, such as network calls, to a
queue or a background thread.
An exporter that holds data, such as a buffer, can add a close() method.
uninstall() calls it, and so does the process on exit.
When it fails¶
An exception from export() never reaches the query. It is logged once, and
after five errors your exporter stops receiving queries while the others carry
on.