Rules And Alerts Migration
This project treats alerting and ruler compatibility as a read path:
vmalertexecutes alerting and recording rules against VictoriaLogs- Loki-compatible read endpoints on the proxy expose those rules and alerts back to Grafana
- the proxy does not implement Loki ruler write APIs
If you already have Loki rule files, use the migration tool to convert them into vmalert rule files.
Migration Model​
Target shape:
- Keep Grafana dashboards and Explore on the Loki datasource that points to the proxy.
- Run
vmalertfor rules and alerts. - Point
vmalertat VictoriaLogs. - Point the proxy
-ruler-backendand-alerts-backendatvmalert. - Let Grafana read rules and alerts through Loki-compatible endpoints on the proxy.
This gives you:
- Loki-compatible rule and alert visibility in Grafana
- VictoriaLogs-native rule execution
- no write-side botched Loki ruler emulation
Tooling​
Convert a Loki-style rule file:
go run ./cmd/rules-migrate -in loki-rules.yaml -out vmalert-rules.yaml
Read from stdin and write to stdout:
cat loki-rules.yaml | go run ./cmd/rules-migrate > vmalert-rules.yaml
Supported inputs:
- Prometheus/Loki-style
groups:rule files - legacy Loki YAML maps such as the classic
/loki/api/v1/rulesshape
Output:
groups:YAML- every group forced to
type: vlogs - every rule
exprtranslated from LogQL into LogsQL
Example​
Input:
groups:
- name: api
interval: 1m
rules:
- alert: HighErrorRate
expr: sum by (app) (rate({app="api-gateway"} |= "error" [5m]))
for: 2m
labels:
severity: page
Output:
groups:
- name: api
interval: 1m
type: vlogs
rules:
- alert: HighErrorRate
expr: '{app="api-gateway"} ~"error" | stats rate() as value by (app)'
for: 2m
labels:
severity: page
The exact generated expression depends on the translator, but the important part is that the output is now valid vmalert + VictoriaLogs rule YAML.
Deploying vmalert​
Minimal example:
services:
vmalert:
image: victoriametrics/vmalert:v1.138.0
command:
- -datasource.url=http://victorialogs:9428
- -rule=/rules/vmalert-rules.yaml
- -rule.defaultRuleType=vlogs
- -notifier.url=http://alertmanager:9093
For local validation without a real Alertmanager:
services:
vmalert:
image: victoriametrics/vmalert:v1.138.0
command:
- -datasource.url=http://victorialogs:9428
- -rule=/rules/vmalert-rules.yaml
- -rule.defaultRuleType=vlogs
- -notifier.blackhole
If your file contains recording rules (record:), add a remote-write target so vmalert can persist those series:
services:
vmalert:
image: victoriametrics/vmalert:v1.138.0
command:
- -datasource.url=http://victorialogs:9428
- -rule=/rules/vmalert-rules.yaml
- -rule.defaultRuleType=vlogs
- -remoteWrite.url=http://victoriametrics:8428/api/v1/write
- -notifier.blackhole
Point the proxy at vmalert:
./loki-vl-proxy \
-backend=http://victorialogs:9428 \
-ruler-backend=http://vmalert:8880 \
-alerts-backend=http://vmalert:8880
Grafana Behavior​
After vmalert is configured and the proxy points at it:
/loki/api/v1/rulesreturns classic Loki-compatible YAML/api/prom/rulesreturns the same classic YAML alias/prometheus/api/v1/rulesreturns Prometheus-style JSON/loki/api/v1/alerts,/api/prom/alerts, and/prometheus/api/v1/alertsreturn JSON alert state- Grafana datasource proxy reads stay consistent with direct paths when
datasource_type=vlogsis set:/api/datasources/proxy/uid/<uid>/prometheus/api/v1/rules?datasource_type=vlogs/api/datasources/proxy/uid/<uid>/prometheus/api/v1/alerts?datasource_type=vlogs
So Grafana can keep reading alert/rule state from the Loki-facing datasource path.
What Converts Cleanly​
These rule patterns generally migrate well:
- stream selectors
- line filters
| json| logfmt- basic metric functions like
rate,count_over_time,sum_over_time - normal
sum by (...),topk(...), and similar aggregation patterns already covered by the translator
What Needs Review​
The migration tool now defaults to a hardened mode:
- safe rules are converted automatically
- risky rules fail conversion with a specific manual-review error
- you can generate a review report with
-report - you can override the safety guard with
-allow-riskyif you intentionally want translated output plus warnings
Example:
go run ./cmd/rules-migrate \
-in loki-rules.yaml \
-out vmalert-rules.yaml \
-report migration-review.txt
If you intentionally want translated output even for risky rules:
go run ./cmd/rules-migrate \
-in loki-rules.yaml \
-out vmalert-rules.yaml \
-report migration-review.txt \
-allow-risky
The migration tool uses the translator, not the proxy runtime.
That means proxy-only runtime emulation does not automatically exist in vmalert rules. Review converted rules if they rely on:
without()on()/ignoring()group_left()/group_right()- subquery
[range:step] histogram()recording rules- other behaviors that the proxy currently emulates above VictoriaLogs rather than translating directly into a backend-native equivalent
For those cases:
- convert the file
- review the translated
expr - validate it directly against VictoriaLogs or
vmalert - simplify or rewrite the rule if needed
Validation Workflow​
Recommended migration flow:
- Convert the Loki rule file with
cmd/rules-migrate. - Start
vmalertwith the generated file. - Call
GET /api/v1/rules?datasource_type=vlogsonvmalert. - Point the proxy at
vmalert. - Verify:
GET /prometheus/api/v1/rulesGET /prometheus/api/v1/alertsGET /loki/api/v1/rulesGET /api/datasources/proxy/uid/<uid>/prometheus/api/v1/rules?datasource_type=vlogs(from Grafana)GET /api/datasources/proxy/uid/<uid>/prometheus/api/v1/alerts?datasource_type=vlogs(from Grafana)
- Confirm Grafana sees the rules/alerts through the Loki datasource path.
Real-Life Test Coverage​
The compose-backed compatibility stack already validates this model with a live backend:
- VictoriaLogs
vmalert- Loki-VL-proxy
- Grafana
See: