Prometheus Metrics
Valerter exposes a /metrics endpoint for Prometheus monitoring.
Configuration
metrics:
enabled: true # Default: true
port: 9090 # Default: 9090
Exposed Metrics
Changed in 2.1.0: the notification counters use the
notifier_namelabel (no morenotifier),valerter_notifier_config_errors_totalis removed, clean stream ends are counted invalerter_stream_ends_totalinstead ofvalerter_reconnections_total, and Telegram counts once per alert. See MIGRATION.md; the changes of 2.0.0 (vl_sourcelabel,valerter_vl_source_up) are in Upgrading from v1.x to v2.0.0.
Counters
| Metric | Labels | Description |
|---|---|---|
valerter_alerts_sent_total |
rule_name, vl_source, notifier_name, notifier_type |
Alerts delivered, once per alert and notifier (an email or telegram alert delivered to at least one recipient or chat counts once) |
valerter_alerts_throttled_total |
rule_name, vl_source |
Alerts blocked by throttling |
valerter_alerts_passed_total |
rule_name, vl_source |
Alerts that passed throttling |
valerter_alerts_dropped_total |
- | Deliveries dropped because a destination queue was full, summed over every destination (an alert dropped for two destinations counts twice) |
valerter_alerts_failed_total |
rule_name, vl_source, notifier_name, notifier_type |
Alerts that permanently failed, once per alert and notifier: retries exhausted, non-retryable response, every recipient or chat failed, template render error at send time, a notifier panic during the send, or a destination missing from the registry (notifier_type="unknown") |
valerter_alerts_truncated_total |
notifier_type, notifier_name |
Alerts whose message was truncated to fit the notifier length limit (Telegram: 4096 codepoints), once per alert. Initialized to 0 for every telegram notifier |
valerter_destination_alerts_dropped_total |
notifier_name, notifier_type |
Alerts dropped because the queue of this destination was full (oldest alert dropped). Initialized to 0 for every notifier |
valerter_email_recipient_errors_total |
rule_name, vl_source, notifier_name |
Email delivery failures, one unit per failed recipient |
valerter_lines_discarded_total |
rule_name, vl_source, reason |
Log lines discarded, one unit per line. reason="oversized": line longer than 1 MiB, dropped whole (its remaining bytes are skipped up to the next \n); reason="invalid_utf8": line that is not valid UTF-8. In both cases the other lines of the stream are kept |
valerter_logs_matched_total |
rule_name, vl_source |
Logs matched by rule (before throttling) |
valerter_notify_errors_total |
rule_name, vl_source, notifier_name, notifier_type |
Permanent notification failures, counted like valerter_alerts_failed_total (once per alert and notifier, render errors included), including notifier_type="unknown" for a destination missing from the registry (also counted in valerter_alerts_failed_total; the startup checks make it unreachable for the daemon). Transient errors that a retry recovers from are not counted |
valerter_parse_errors_total |
rule_name, vl_source, error_type |
Parsing errors: error_type="invalid_json" (any rule) or error_type="regex_no_match" (rules with a regex parser) |
valerter_reconnections_total |
rule_name, vl_source |
VictoriaLogs reconnections after a failure: connection error, HTTP error response or error while reading the stream. Clean stream ends are counted in valerter_stream_ends_total |
valerter_rule_panics_total |
rule_name, vl_source |
Rule task panics. The task is auto-restarted with exponential backoff (5 s to 5 min), never abandoned: a steady increase means a task panicking in a loop |
valerter_rule_errors_total |
rule_name, vl_source |
Fatal rule errors |
valerter_stream_ends_total |
rule_name, vl_source |
Clean VictoriaLogs stream ends (EOF without error), each followed by a reconnection. Not a failure: a proxy closing idle streams makes it grow |
valerter_telegram_chat_errors_total |
rule_name, vl_source, notifier_name |
Telegram delivery failures, one unit per failed chat. A chat delivered through the plain-text fallback is not a failure |
Series initialized at startup
Every series is created at 0 when valerter starts, with exactly the labels it
is emitted with, so rate() and increase() work from the first event:
- per
(enabled rule, resolved source)pair: therule_name,vl_sourcecounters above,valerter_lines_discarded_totalfor both reasons,valerter_parse_errors_totalfor each possibleerror_type,valerter_last_query_timestampandvalerter_query_duration_seconds; - per
(enabled rule, resolved source, rule destination)triplet:valerter_alerts_sent_total,valerter_notify_errors_total,valerter_alerts_failed_total, plusvalerter_email_recipient_errors_totalorvalerter_telegram_chat_errors_totalfor anemailortelegramdestination. A notifier used by no enabled rule gets none of these series; - per notifier:
valerter_destination_queue_size,valerter_destination_alerts_dropped_total, andvalerter_alerts_truncated_totalfor atelegramnotifier; - per source targeted by at least one enabled rule:
valerter_vl_source_up. A declared source that no enabled rule tails gets no series.
Notifier configuration errors (such as an undefined ${VAR}) have no metric:
they stop valerter at startup, before the metrics endpoint opens, with an
ERROR log and exit code 1.
Gauges
| Metric | Labels | Description |
|---|---|---|
valerter_queue_size |
- | Pending deliveries summed over every destination queue (an alert waiting for two destinations counts twice). Each destination queue holds at most 100 alerts, so this sum can reach 100 × number of notifiers |
valerter_destination_queue_size |
notifier_name, notifier_type |
Alerts pending in the queue of this destination (0 to 100). Initialized to 0 for every notifier |
valerter_last_query_timestamp |
rule_name, vl_source |
Unix timestamp of the last chunk received from the stream; 0 until the first one. VictoriaLogs sends no keepalive, so it does not move while the query matches nothing |
valerter_vl_source_up |
vl_source |
Per-source VictoriaLogs reachability (1=connected, 0=disconnected), for every source targeted by at least one enabled rule. 0 at startup, 1 as soon as a connection succeeds, back to 0 only after 3 consecutive failures of a task (connection error, HTTP error response or error while reading the stream; a clean stream end is not a failure). All the (rule, source) tasks of a source write the same series, last writer wins: one task failing 3 times in a row sets the whole source to 0, and the next successful connection of any task sets it back to 1. Replaces v1.x valerter_victorialogs_up{rule_name}. |
valerter_uptime_seconds |
- | Time since valerter started |
valerter_build_info |
version |
Build information (always 1) |
Summaries
| Metric | Labels | Description |
|---|---|---|
valerter_query_duration_seconds |
rule_name, vl_source |
VictoriaLogs query latency (time to first chunk). Exposed as a Prometheus summary: valerter_query_duration_seconds{quantile="..."}, valerter_query_duration_seconds_sum and valerter_query_duration_seconds_count (no _bucket series) |
Reconnect Backoff Jitter
Reconnect attempts apply ±10% uniform jitter per (rule, source) task on top
of the existing exponential backoff (1s base, 60s cap). When N sources behind
a flapping load balancer would otherwise reconnect in lock-step, the jitter
spreads attempts in a [0.9·D, 1.1·D] window so the herd dissolves over a few
cycles. The jitter is hardcoded (not configurable) and never drops
the effective delay below 100ms.
Prometheus Scrape Configuration
scrape_configs:
- job_name: 'valerter'
static_configs:
- targets: ['localhost:9090']
Example Alerting Rules
Monitor Valerter itself with these Prometheus alerting rules:
groups:
- name: valerter
rules:
# No data received by a (rule, source) task for an hour.
# valerter_last_query_timestamp is 0 until the first chunk, then the time
# of the last chunk received: VictoriaLogs sends no keepalive, so a rule
# whose query matches no log is quiet, not broken. Bound the expression
# on "> 0" and pick a delay longer than the normal silence of your
# rules; detect real outages with valerter_vl_source_up and
# rate(valerter_reconnections_total[5m]) instead.
- alert: ValerterNoDataReceived
expr: valerter_last_query_timestamp > 0 and time() - valerter_last_query_timestamp > 3600
for: 5m
labels:
severity: info
annotations:
summary: "Valerter rule {{ $labels.rule_name }} received nothing from {{ $labels.vl_source }}"
description: "No log received for over an hour; normal if the query rarely matches"
# Repeated reconnections after failures
- alert: ValerterReconnecting
expr: rate(valerter_reconnections_total[5m]) > 0
for: 15m
labels:
severity: warning
annotations:
summary: "Valerter rule {{ $labels.rule_name }} keeps reconnecting to {{ $labels.vl_source }}"
description: "Connection or stream errors for 15 minutes; check the logs for 'Connection failed'"
# VictoriaLogs source unreachable (per-source gauge, v2.0.0)
- alert: ValerterVlSourceDown
expr: valerter_vl_source_up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Valerter disconnected from VictoriaLogs source {{ $labels.vl_source }}"
description: "Source {{ $labels.vl_source }} is unreachable. Check network and VictoriaLogs health."
# Alerts failing to send
- alert: ValerterAlertsFailing
expr: rate(valerter_alerts_failed_total[5m]) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Valerter alerts failing for {{ $labels.notifier_name }}"
description: "Alerts are failing to send via {{ $labels.notifier_type }} notifier"
# Too many alerts throttled (potential tuning needed)
- alert: ValerterHighThrottleRate
expr: rate(valerter_alerts_throttled_total[1h]) > 100
for: 10m
labels:
severity: info
annotations:
summary: "High throttle rate on rule {{ $labels.rule_name }}"
description: "Consider adjusting throttle settings if this is unexpected"
# A destination queue filling up (each queue holds at most 100 alerts).
# Do not put an absolute threshold on valerter_queue_size: it is a sum
# over every destination and can reach 100 x number of notifiers.
- alert: ValerterQueueBacklog
expr: max by (notifier_name) (valerter_destination_queue_size) > 50
for: 5m
labels:
severity: warning
annotations:
summary: "Valerter queue backlog for {{ $labels.notifier_name }}"
description: "{{ $value }} alerts pending for {{ $labels.notifier_name }}, its notifications are delayed"
# A destination dropping alerts (queue full)
- alert: ValerterAlertsDropped
expr: rate(valerter_destination_alerts_dropped_total[5m]) > 0
labels:
severity: warning
annotations:
summary: "Valerter dropping alerts for {{ $labels.notifier_name }}"
description: "The queue of {{ $labels.notifier_name }} is full: its oldest alerts are dropped"
# Rule panics (indicates bugs). Panicked tasks are restarted forever
# with a 5 s to 5 min backoff, so a looping panic shows up here.
- alert: ValerterRulePanic
expr: increase(valerter_rule_panics_total[1h]) > 0
labels:
severity: warning
annotations:
summary: "Valerter rule {{ $labels.rule_name }} panicked on {{ $labels.vl_source }}"
description: "{{ $value }} panics in the last hour; the task is auto-restarted with backoff. Check logs for 'Rule task panicked - CRITICAL'."
Key Metrics to Monitor
Health
valerter_vl_source_up- Per-source VictoriaLogs reachability (1=connected, 0=disconnected)valerter_uptime_seconds- Process uptime (detect restarts)
Performance
valerter_destination_queue_size- Notification backlog per destination (valerter_queue_sizefor the total)valerter_query_duration_seconds- Query latency
Alerting Effectiveness
valerter_alerts_sent_total- Successful alertsvalerter_alerts_throttled_total- Throttled alerts (tuning indicator)valerter_alerts_failed_total- Failed alerts (notifier issues)
Errors
valerter_parse_errors_total- Log parsing issuesvalerter_notify_errors_total- Permanent notification failures (after retries, or not retryable)valerter_email_recipient_errors_total/valerter_telegram_chat_errors_total- One unit per failed recipient or chat, even when the alert reached other recipients or chatsvalerter_rule_panics_total- Critical: indicates bugs
See Also
- Configuration - Enable/configure metrics
- Architecture - How metrics fit into the pipeline