Datadog Metrics
CritterWatch can pull throughput, failure-rate, baseline, and dead-letter rate from Datadog's metrics API instead of Prometheus or VictoriaMetrics. The 0.5+ alert evaluator, the per-service summary, and the various trend visualizations all work transparently against whichever metrics backend the operator has configured.
What CritterWatch needs from Datadog
- A Datadog API Key and a Datadog Application Key
- The site your account is hosted on (
us1/us3/us5/eu1/ap1) - Your Wolverine services already shipping OTel metrics to Datadog. Datadog accepts OTLP natively or via the Datadog Agent — either path is fine.
The same keys you use for Datadog Tracing work here. The app key only needs read access to the Metrics Read scope.
How to wire it up
In your CritterWatch host startup:
services.AddCritterWatchMetricsDataSource<DataDogMetricsDataSource, DataDogMetricsDataSourceOptions>(
"datadog",
opts =>
{
opts.ApiKey = builder.Configuration["Datadog:ApiKey"]!;
opts.AppKey = builder.Configuration["Datadog:AppKey"]!;
opts.Site = builder.Configuration["Datadog:Site"] ?? "us1";
});Use your existing secret store — env vars, Azure Key Vault, AWS Secrets Manager, etc. CritterWatch reads from IConfiguration and never persists the keys.
Per-service routing
services.AddCritterWatchMonitoring(opts =>
{
opts.MetricsDataSource("datadog");
});Same name you used in the host registration. The operator can override per-service via Settings → Metrics Data Sources.
Which metrics CritterWatch reads
CritterWatch reads the standard Wolverine OTel metrics that Datadog ingests automatically:
| What | Wolverine metric | Datadog query |
|---|---|---|
| Executions per minute | wolverine.message.executions | sum:wolverine.message.executions{service:X}.as_count() |
| Failures per minute | wolverine.message.failures | sum:wolverine.message.failures{service:X}.as_count() |
| Mean execution time | wolverine.message.execution.time | avg:wolverine.message.execution.time{service:X} |
| Dead-letter rate | wolverine.dead_letter.count | sum:wolverine.dead_letter.count{service:X}.as_count() |
If your Datadog org renames metrics (custom recording rules, etc.), CritterWatch won't find them under the canonical names — surface the gap with the Datadog Metrics Explorer first to confirm the names you're actually emitting.
Per-message-type breakdown
Some CritterWatch features (dead-letter breakdown table, message-type alert thresholds) need metrics tagged by messaging.message_type. Datadog stores OTel resource + span attributes as tags automatically when ingesting OTLP, so the breakdown query is:
sum:wolverine.dead_letter.count{service:X} by {messaging.message_type, exception.type}.as_count()If Datadog isn't surfacing that grouping, your OTel exporter is probably stripping span attributes before they reach Datadog. The fix is usually to set OTEL_RESOURCE_ATTRIBUTES_AS_LABELS=true on the Datadog Agent (or the equivalent on the Otel-collector-to-Datadog exporter).
When a metric isn't available
CritterWatch's IMetricsDataSource contract returns empty snapshots (zero counts, null timestamps) when a metric isn't found — same shape as Prometheus / VictoriaMetrics impls. The operator sees blank cells in the affected widgets, not error messages. The Settings page Test button validates the API key + Site but not the per-metric availability; verify metric names by clicking through a Service detail page after wiring up and confirming the throughput cards populate.
Multi-region
Register multiple instances if you split metrics across Datadog regions:
services.AddCritterWatchMetricsDataSource<DataDogMetricsDataSource, DataDogMetricsDataSourceOptions>(
"datadog-us",
opts => { opts.ApiKey = ...; opts.Site = "us1"; });
services.AddCritterWatchMetricsDataSource<DataDogMetricsDataSource, DataDogMetricsDataSourceOptions>(
"datadog-eu",
opts => { opts.ApiKey = ...; opts.Site = "eu1"; });Each monitored service picks one via opts.MetricsDataSource("datadog-us") or "datadog-eu". Operators can override per-service in Settings.
