Igor Serko
12/02/2025, 4:14 PMMarvin
12/02/2025, 4:14 PMMarvin
12/02/2025, 4:19 PMPREFECT_API_ENABLE_METRICS=true
- PREFECT_CLIENT_METRICS_ENABLED=true (client endpoint defaults to http://localhost:4201/metrics)
- Configure the Datadog Agent (OpenMetrics) to scrape these endpoints:
init_config:
instances:
- openmetrics_endpoint: <http://your-prefect-api:4200/metrics>
namespace: prefect_api
metrics:
- prefect_*
- openmetrics_endpoint: <http://localhost:4201/metrics>
namespace: prefect_client
metrics:
- prefect_*
- Datadog docs: OpenMetrics (Prometheus) integration
Notes:
- The API server /metrics endpoint includes Prefect server-side metrics; the client endpoint exposes per-process client metrics (useful on workers).
- From these, you can build dashboards/alerts (e.g., flow run events observed, worker websocket connections, etc.). If you need specific KPIs like “queue backlog,” consider #3 below.
2) Events → Datadog (for flow/pool/queue state changes)
- Prefect emits structured events such as prefect.flow-run.started/completed/failed, worker claimed work, etc.
- Use a Prefect Automation with a Webhook action to send selected events to Datadog Logs or Events intake (great for alerts on failures or stuck queues).
- Datadog logs HTTP intake: Datadog Logs HTTP intake API
3) Custom metrics for work pools/queues
- If you want explicit metrics like “queue length,” “late runs,” or “runs failing by deployment,” run a small periodic job that queries the Prefect API and emits DogStatsD gauges.
Example outline:
from prefect import get_client
from datadog import initialize, statsd
# initialize(api_key=..., app_key=...) if using the Datadog library directly
# or rely on the Datadog Agent’s DogStatsD on UDP :8125
async def emit_metrics():
async with get_client() as client:
# work pools / queues
work_pools = await client.read_work_pools()
work_queues = await client.read_work_queues()
statsd.gauge('prefect.work_pools.count', len(work_pools))
statsd.gauge('prefect.work_queues.count', len(work_queues))
# example: failed flow runs in the last window (filter as needed)
# ...build filters and count, then emit:
# statsd.gauge('prefect.flow_runs.failed.count', n_failed)
- This gives you precise KPIs for dashboards/alerts.
4) Logs to Datadog
- Prefect uses standard Python logging; you can add a handler that forwards to Datadog (HTTP intake or Agent). This is useful if you want unified log search and alerts in Datadog.
Next steps / questions to tailor the setup
- Are you on Prefect Cloud or OSS Server?
- Where do your workers run (Kubernetes, ECS, VMs)? This affects where to run the Datadog Agent and how to point it to the metrics endpoints.
- Do you want just metrics, just logs, or both? And any key SLOs you want to alert on (e.g., queue backlog, late runs, failure rate)?
If you share your environment, I can provide a drop-in Datadog Agent config and a small “queue backlog” exporter example that fits your deployment.Igor Serko
12/02/2025, 4:20 PMIgor Serko
12/02/2025, 4:21 PMMarvin
12/02/2025, 4:21 PMMarvin
12/02/2025, 4:27 PM{
"title": "Prefect Late Runs",
"text": "High lateness on {{ event.resource.name }}",
"tags": [
"source:prefect",
"type:lateness",
"queue:{{ event.resource.name }}"
]
}
Docs: Datadog Events API
- Or Datadog Logs intake: POST https://http-intake.logs.datadoghq.com/v1/input/YOUR_DD_API_KEY with headers Content-Type: application/json and a JSON body similar to:
{
"message": "Prefect late runs over threshold",
"ddsource": "prefect",
"ddtags": "queue:{{ event.resource.name }}"
}
Docs: Datadog Logs HTTP intake
2) Queue backlog (small monitor + DogStatsD metrics)
- Backlog = flow runs in Scheduled state that haven’t been picked up yet.
- Overdue backlog = scheduled in the past (scheduled start time < now).
- Late runs = flow runs in state Late (Cloud marks these automatically after a grace period).
Use this tiny async job (run every 1–5 minutes) to emit metrics to Datadog:
```
import asyncio
import os
from datetime import datetime, timezone
from datadog import initialize, statsd
from prefect import get_client
from prefect.client.schemas.filters import (
FlowRunFilter,
FlowRunFilterState,
FlowRunFilterStateName,
FlowRunFilterNextScheduledStartTime,
WorkQueueFilter,
WorkQueueFilterName,
)
# If you prefer DogStatsD via Agent (recommended), you do NOT need initialize()
# Just ensure the Agent is reachable on UDP 8125 and DD_AGENT_HOST/DD_DOGSTATSD_PORT are set.
# If you'd rather use the Datadog Metrics API directly, uncomment and set your keys:
# initialize(api_key=os.environ["DD_API_KEY"], app_key=os.environ["DD_APP_KEY"])
WORK_QUEUE_NAMES = os.getenv("WORK_QUEUE_NAMES", "default").split(",")
async def emit_queue_metrics():
now = datetime.now(timezone.utc)
async with get_client() as client:
for queue in [q.strip() for q in WORK_QUEUE_NAMES if q.strip()]:
# Total backlog: all Scheduled
backlog = await client.flow_runs.count_flow_runs(
flow_run_filter=FlowRunFilter(
state=FlowRunFilterState(
name=FlowRunFilterStateName(any_=["Scheduled"])
)
),
work_queue_filter=WorkQueueFilter(
name=WorkQueueFilterName(any_=[queue])
),
)
# Overdue backlog: Scheduled with next_scheduled_start_time < now
overdue = await client.flow_runs.count_flow_runs(
flow_run_filter=FlowRunFilter(
state=FlowRunFilterState(
name=FlowRunFilterStateName(any_=["Scheduled"])
),
next_scheduled_start_time=FlowRunFilterNextScheduledStartTime(
before_=nowMarvin
12/02/2025, 4:27 PM