Playbook — Manage Mezmo (LogDNA) alerts via Terraform
Status: scaffolding shipped (#4185); native bms-1 no-logs alert codified as DISABLED at source (#4197). terraform apply is a sys-admin follow-up.
IaC location: terraform/mezmo/
Related ops docs: docs/mezmo-operations.md, docs/logdna-operations.md, docs/playbooks/mezmo-key-rotation.md
1. Why Terraform for Mezmo
Mezmo Views/Alerts are configured by clicking the dashboard, so their definitions live nowhere
in git — they can be silently reverted by a UI edit or a re-import (this is exactly the failure
mode called out for the MongoTimeoutError view in docs/mezmo-operations.md). The 14–16 Jul
“bms-1 no logs” false positives were a mis-tuned absence alert that could only be fixed by hand.
Codifying Views/Alerts in terraform/mezmo/ makes them reviewable, diffable, and reproducible,
and lets us disable/retune the absence window + remediation text through a PR. This is
complementary to the runtime suppression guard already deployed in the mezmo-alert-router
n8n workflow — one fixes the alert at the source (Mezmo config), the other is defense-in-depth at
the router.
Decision (#4197) — the bms-1 native alert is DISABLED at source. The native View-alert fired
direct to Discord, bypassing the n8n guard, so it kept producing false “no logs for 10+ min” pings
even while pinbox24_log_lines_5m_total showed a healthy stream (~17 lines / 5 min). The guarded
n8n path already suppresses nologs while logs flow, so it is now the single canonical no-logs
gate. logdna_view.bms1_no_logs is codified with alert_enabled = false (default): the view is
kept as a saved search but rendered with no alert channel, so it can never fire. Re-enabling is
a one-line var flip (alert_enabled = true) that restores the retune config (30m window,
mezmo-agent remediation, n8n webhook) preserved in main.tf.
2. TWO Mezmo Terraform providers — do not mix them up
| Provider | Product | Manages | Ours? |
|---|---|---|---|
logdna/logdna | Log Management (app.mezmo.com) | logdna_view, logdna_alert, logdna_archive, logdna_category, logdna_index_rate_alert, logdna_ingestion_exclusion, logdna_key, logdna_member, logdna_stream_config, logdna_stream_exclusion | ✅ YES — where our bms-1 logs land via mezmo-agent/logdna-agent. |
mezmo/mezmo | Pipeline (sources→processors→destinations) | Pipeline objects | ❌ Not used — we do not route through Mezmo Pipeline today. |
terraform/mezmo/ uses logdna/logdna exclusively.
3. Log flow being managed
logdna-agent (systemd, bms-1) → Mezmo log ingest → Views/Alerts → mezmo-alert-router
n8n webhook (Sc2AKCdslinnSvWs, …/webhook/mezmo-alert) → Discord embed + optional GH issue.
The bms-1 no-logs alert is a logdna_view with an inline channel set to operator = "absence":
it fires when no matching line arrives on hosts=["bms-1"] within the trigger window. Per
#4197 that channel is now gated behind var.alert_enabled (default false) — the view exists but
emits no channel, so the native alert is disabled and only the n8n-guarded path can page.
4. Credentials — reuse the existing service key
The logdna/logdna provider’s servicekey is the Mezmo Organization service key
(Settings → Organization → API Keys). We already have one:
P24_INFRA_MEZMO_SERVICE_KEY(sts_…) insecrets/monitoring.env.sops— used today byscripts/mezmo-manage.py+ cost-exporter againsthttps://api.mezmo.com/v1/config/*, the same endpoints the Terraform provider drives.
Therefore issue #4185 deliverable (a) — “mint MEZMO_SERVICE_KEY” — is most likely a no-op:
reuse P24_INFRA_MEZMO_SERVICE_KEY. A new key is only warranted if that key is found to lack
management-write scope for Views/Alerts (Mezmo org service keys are org-wide, so it should
suffice). Any actual SOPS write is a secret-manager action — a dev/sys-admin session must not
write SOPS. Supply the key to Terraform at runtime, never in HCL:
export TF_VAR_mezmo_service_key="$(sops -d --input-type dotenv --output-type dotenv \
secrets/monitoring.env.sops | grep '^P24_INFRA_MEZMO_SERVICE_KEY=' | cut -d= -f2-)"5. Remote state (Wasabi S3)
s3://p24-infra/terraform/mezmo/terraform.tfstate, region eu-central-2, endpoint
https://s3.eu-central-2.wasabisys.com. State is never committed (terraform/mezmo/.gitignore)
— it can contain the service key. Backend credentials come from the environment
(AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY = Wasabi p24-infra IAM).
6. Runbook — IMPORT before APPLY ⚠️
The bms-1 no-logs view already exists in Mezmo. apply without importing first creates a
duplicate alert. Order of operations (sys-admin, after the PR merges to main):
cd terraform/mezmo
# 1. export TF_VAR_mezmo_service_key + AWS_* (see §4/§5, and README.md)
./import.sh # init + discover the live view id
terraform import logdna_view.bms1_no_logs <VIEW_ID>
terraform plan # alert_enabled=false ⇒ plan REMOVES the alert channel
terraform apply # disables the native no-logs alert at source (#4197)After apply, record the view id in docs/mezmo-operations.md §views (the bms1_no_logs_view_id
output) and confirm the native no-logs Discord ping no longer fires on a healthy stream.
7. Extending — new views/alerts
- Add a
logdna_view(inline channel) orlogdna_alert+logdna_view(presetid) tomain.tf. - If a counterpart already exists in the Mezmo UI → import it first, then reconcile.
- Keep alert payloads compatible with the
mezmo-alert-router“Prepare Alert” node (alert_type,host,severity,summary,remediation). - PR to
main;applyis sys-admin post-merge.
8. Gotchas
- Absence window too tight → false positives (the 14–16 Jul incident). 30m is the tuned default.
- Host label — Mezmo may key on the raw hostname, not the friendly
bms-1. Confirm from the imported state / API before trustingvar.bms1_host. - Remediation must point at
mezmo-agent, notpm2— rootpm2 listis empty post-#3171. - Provider default URL is the legacy
api.logdna.com— we override toapi.mezmo.com. logdna_viewPUT/import quirks (bodyTemplate object vs string,alertidomission) are documented indocs/mezmo-operations.md; Terraform handles the round-trip, but expect the first post-importplanto show cosmetic diffs to reconcile.