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: