VictoriaLogs
pg addon install victorialogs runs VictoriaLogs — a fast, cost-effective log database from the VictoriaMetrics family — as a managed container from the official docker.io/victoriametrics/victoria-logs image. Like VictoriaMetrics and Prometheus it is a top-level addon: it fronts no single PostgreSQL instance (it ingests logs from many sources), so it is not attached to any one of them. VictoriaMetrics keeps metrics, VictoriaLogs keeps logs, Grafana visualises both — and all three share the same lifecycle shape (single container, host networking on Linux, one web port from its own pool, persistent data dir, restart policy).
VictoriaLogs is the exact mirror of the VictoriaMetrics addon in how it is configured: it needs no config file at all — everything is passed as CLI flags after the image name (-storageDataPath / -httpListenAddr / -retentionPeriod / custom flags via --extra-arg). So pgcli passes these flags directly when creating the container; there is no config to render, no SIGHUP reload, no chown needed (the image runs as root). One container serves everything on a single HTTP port: ingestion (JSON Lines, Elasticsearch-compatible bulk, syslog, OTLP), LogsQL queries, and the built-in UI.
There is NO web login/password. VictoriaLogs ships no authentication at all. Its HTTP API can ingest and query arbitrary logs and be loaded by expensive LogsQL queries, so a remote-exposed instance is guarded only by the network boundary — your firewall, or
--listen 127.0.0.1for loopback. Treat exposing it like exposing an unauthenticated read/write console, not like a password-protected dashboard.
Platform: Linux is the tested platform. The design supports macOS (the image is multi-arch; the container runs under the podman machine VM on the
pgcli-netbridge with the port published), but it has not been validated there yet.
Parameters
| Flag | Default | Description |
|---|---|---|
--name |
vl |
Instance name (map key) |
--image |
docker.io/victoriametrics/victoria-logs:v1.53.0 |
Image override |
--port |
auto (base 9428) | Host web port; auto-allocated from victorialogs_start_port |
--listen |
0.0.0.0 |
Bind address — defaults to every interface; use 127.0.0.1 for loopback-only (see the exposure warning above) |
--retention |
binary default | Data retention as a duration (30d, 3months, 1y, …), passed verbatim as -retentionPeriod. Omitting it keeps the victoria-logs default |
--extra-arg |
— | Extra CLI flag passed to the binary (repeatable); appended last so last-wins overrides earlier flags. E.g. --extra-arg -search.maxQueryDuration=60s |
--data-dir |
auto | Data directory override (default under the base dir) |
--force |
false | Recreate even when running — to apply changed ports / listen / retention / extra-args |
The data directory holds VictoriaLogs’s log storage. It survives pg addon remove (delete it with --clean-data), so reinstalling under the same name revives stored logs. The image runs as root (unlike Prometheus’s uid 65534), so no pre-chown of the data dir is needed.
Install
The command pulls the image if needed, creates the container, and prints the URL and retention:
VictoriaLogs is ready to ingest and query immediately. Open http://<host>:9428/select/vmui/ for the built-in web UI (the root path / is just an index of useful endpoints), or query via the HTTP API:
Re-running install on a running instance recreates it when the config actually changed (ports, listen, retention, extra-args), and leaves it alone when it didn’t; --force recreates the container even when config is unchanged.
VictoriaLogs does not support hot config reload, so all changes require container recreation — same as VictoriaMetrics. This is simpler than Prometheus (no config file to render, no reload signal), but means brief interruption when changing settings.
Web UI
Every VictoriaLogs instance ships with a built-in web UI (VMUI) — there is no extra component to install. Open:
The root path (/) is only an index of useful HTTP endpoints; the UI lives under /select/vmui/.
The UI is a LogsQL console for logs:
- Query — type a LogsQL query (e.g.
app:demo,level:error,error app:demo-api) and pick the time range; results update as you run the query. - Views — switch between
Group(rows grouped by stream fields),Table(click a row to expand every field),JSON(raw/select/logsql/queryresponse), andLive(live tail of matching logs as they arrive). - Exploration — field and stream pickers list the stored field names/values (backed by
/select/logsql/field_names,field_values,facets, …), so you can build queries without knowing the schema up front.
For example, ingest one line and search for it in the UI (app:demo):
The UI shares the same port and the same no-authentication posture as the HTTP API: anyone who can reach the port can search and also ingest logs. Restrict it with --listen 127.0.0.1 or a firewall, as described above.
Common queries
Queries use LogsQL. The examples below run against the HTTP query API; the same strings work in the VMUI at /select/vmui/.
The response is newline-delimited JSON, one object per log entry.
Always include a
_time:filter when querying production data. Without one, VictoriaLogs scans every log in the retention period.
| Goal | Query |
|---|---|
| All logs from the last 5 minutes | _time:5m |
| Full-text search | _time:15m error |
| Match specific fields | _time:1h app:demo level:error |
| Exact value (case-sensitive) | _time:1h level:=error |
| Regex match (RE2) | _time:1h path:~"/api/v[0-9]+/" |
| Phrase / prefix match | _time:1h _msg:"payment timeout" / _time:1h _msg:timeout* |
| Numeric comparison | _time:1h request_duration:>1s |
| AND / OR / NOT | _time:5m level:error -app:buggy / _time:5m (level:error OR level:warn) |
| Stream filter | _time:1h {app="demo"} |
| Search every field | _time:5m | *:timeout |
| Newest first, top 10 | _time:5m error | sort by (_time) desc | limit 10 |
| Keep only some fields | _time:5m error | fields _time, level, _msg |
| Count by level | _time:1h | stats by (level) count() |
| Total count | _time:1h error | stats count() errors |
| Unique values with hit counts | _time:1h | uniq by (user) with hits |
| Top N values | _time:1d level:error | top 10 (path) |
Notes:
field:wordmatches the word within that field;field:=valueis an exact match andfield:~"regex"is a regex match. Negated forms are-filter,!=and!~.- Time filters accept durations (
5m,1h,30d), absolute timestamps (2026-10-23Z,2026-10-23T10:00:00Z) and ranges (_time:[2026-10-01Z, 2026-10-23Z]). - Pipes run left to right, so filters must come before
sort,limit,stats,topand the other processing stages.
Ingestion: vlagent, HTTP APIs, collectors
pgcli runs the VictoriaLogs backend only — how logs reach it is up to you. There are three routes.
vlagent (official agent)
vlagent is the official log agent for VictoriaLogs — the log counterpart of vmagent (vmagent ships metrics only; do not use it for logs). It accepts the same HTTP ingestion protocols as VictoriaLogs on its own port (9429 by default), can tail log files from disk, and forwards everything to VictoriaLogs via -remoteWrite.url, which must end with /insert/native. pgcli runs and manages it for you — see the vlagent addon page for the full reference:
The first form tracks no log files: without --log-path/--include (or -kubernetesCollector via --extra-arg), vlagent only receives logs pushed to it over HTTP and forwards them. --log-path accepts any host file or directory; with no --include, a directory defaults to <dir>/**/*.log and a file to itself. The globs are matched inside the container, which is why pgcli mounts each host path at the identical absolute path.
Use vlagent when you need:
- Replication / HA — repeat
--remote-write-urlfor every VictoriaLogs instance. vlagent copies each log to all of them and keeps an independent on-disk buffer per URL (-remoteWrite.tmpDataPath, capped by-remoteWrite.maxDiskUsagePerURL); logs collected while a backend is down are replayed when it returns. - Kubernetes Pod logs — pass
--extra-arg -kubernetesCollectorand mount the host’s/var/log(plus/var/libwith the Docker runtime so runtime symlinks resolve) via--log-path. It follows/var/log/podsand/var/log/containers, adds container metadata, and checkpoints its read position in the data dir under-tmpDataPath. - Files on disk —
--log-path /var/log/nginx --include '/var/log/nginx/*.log'(globs must point at files, not directories). By defaulthostnameandfilebecome stream fields, and reading checkpoints/buffers live in the addon’s data dir.
For a single, stable VictoriaLogs instance, sending logs directly (below) is simpler — that is the recommended default.
HTTP APIs
VictoriaLogs exposes several ingestion endpoints on the same port as the UI and query API:
| Endpoint | Format | Notes |
|---|---|---|
/insert/jsonline |
JSON Lines (ndjson) | Requires Content-Type: application/json; without it the request returns 200 but the payload is silently dropped |
/insert/elasticsearch/_bulk |
Elasticsearch / OpenSearch bulk | Point Filebeat / Logstash / Fluent Bit Elasticsearch outputs here |
/insert/loki/api/v1/push |
Loki JSON push | Point Promtail / Grafana Alloy / Loki clients here |
/insert/opentelemetry/v1/logs |
OTLP/HTTP logs | Point an OpenTelemetry Collector exporter here |
| syslog TCP / UDP / Unix | RFC3164 / RFC5424 | Enable via --extra-arg -syslog.listenAddr.tcp=:514 (or .udp / .unix), then recreate |
All HTTP ingestion endpoints accept the same tuning parameters, either as query-string args or VL-* headers: _msg_field (field holding the log message, e.g. message), _time_field (e.g. @timestamp), _stream_fields (comma-separated fields that define a log stream), extra_fields (env=prod), ignore_fields, decolorize_fields, and debug=1 (log the payload instead of storing it). Use them when your collector emits a schema VictoriaLogs does not auto-detect.
Log collectors
Any collector that can speak one of the formats above works; pgcli installs and configures none of them. Commonly used ones, each with an official setup guide:
| Collector | Send to |
|---|---|
| Filebeat | Elasticsearch output → /insert/elasticsearch/_bulk |
| Logstash | Elasticsearch or HTTP output |
| Fluent Bit / Fluentd | Elasticsearch or HTTP output |
| Vector | http sink → /insert/jsonline, or Elasticsearch sink |
| Promtail / Grafana Alloy | Loki push → /insert/loki/api/v1/push |
| OpenTelemetry Collector | OTLP/HTTP exporter → /insert/opentelemetry/v1/logs |
| Telegraf | http output → jsonline |
| journald | Vector / Fluent Bit journald source → jsonline, or vlagent |
| rsyslog / syslog-ng | syslog listener (-syslog.listenAddr.*) |
| Datadog Agent | Datadog intake API |
Collectors can also point at a vlagent instance (port 9429) instead of VictoriaLogs directly — useful when you want buffering, replication, or a single egress point.
Custom flags (--extra-arg)
VictoriaLogs accepts many CLI flags for tuning cache sizes, query limits, ingestion rates, and more. Pass them via --extra-arg (repeatable):
Extra args are appended last to the container’s command line, so they override earlier flags via last-wins semantics. This lets you tune VictoriaLogs beyond pgcli’s first-class knobs without editing any config file. Verify the flags took effect (the binary does not print them in its logs):
Listening and exposure
VictoriaLogs’s Listen defaults to 0.0.0.0: the container shares the host’s network namespace, so the UI and API are reachable on every interface at the assigned port. This matches VictoriaMetrics’s default for the same practical reason (log shippers and Grafana on other hosts need to reach it) — but there is no password behind it. Anyone who can reach the port can run arbitrary LogsQL and read your stored logs. For a loopback-only deployment pass --listen 127.0.0.1 (recreate with --force); pg addon list then shows http://127.0.0.1:<port>/. Otherwise, restrict access at the firewall.
Ports
Each VictoriaLogs instance owns a single port: the web UI/API. It is allocated from a pool with base victorialogs_start_port (default 9428 — VictoriaLogs’s conventional HTTP port), incrementing for every additional instance and skipping ports already taken by any managed container or the used_ports list. The allocation is written into pg.yaml, so a reinstall never re-hands-out a port another addon is using. 9428 shares no number with VictoriaMetrics (8428), vmcluster (8480-8484), Prometheus (9090), Grafana (3000), pgAdmin (5050), or nginx (8080); an explicit --port still wins.
Configuration
There is no config file — everything is passed as CLI flags to the victoria-logs binary (-storageDataPath, -httpListenAddr, -retentionPeriod, plus any extra_args). retention is stored as a duration string (omitted = binary default), and extra_args is a list of CLI flags appended last.
List
There are no credentials to reveal — VictoriaLogs has none — so --show-password shows nothing extra for it.
Start and stop
Containers run with podman’s unless-stopped restart policy, so they come back automatically with the podman service after a host reboot. start/stop manage them explicitly:
Autostart on boot
This flags the instance in pg.yaml and installs/refreshes a boot service (a systemd --user unit on Linux, a LaunchAgent on macOS) that runs pg start --autostart. A boot-time start only brings the container up — the log data dir already exists, so stored logs survive the reboot. Disable with pg autostart disable --victorialogs --name vl; see Autostart for the full mechanism.
Remove
Under rootless podman, --clean-data deletes the data dir through podman unshare rm — VictoriaLogs writes as root (container uid 0), which maps to a subordinate uid the host user cannot rm directly.
Troubleshooting
- Ingestion answers 200 but queries return nothing — the JSON Lines endpoint requires
Content-Type: application/json; without it VictoriaLogs accepts the request and silently drops the payload (vl_rows_ingested_total{type="jsonline"}on/metricsstays 0). Add the header, or use an ingestion client that sets it. - A query returns no data — confirm VictoriaLogs is running (
pg addon listshowsrunning), the health endpoint responds (curl -s http://<host>:<port>/-/healthy), and you’re querying the correct time range and stream filters (_stream:prefix,_time:bounds). Checkpodman logs <container>for ingestion errors. - Install fails with “container already exists” — the container name is derived from
--nameand the namespace; use--forceto recreate, orpg addon removefirst to clean up a partial install. - Extra args didn’t take effect —
--extra-argis applied at container creation time, not runtime. Reinstall with--forceto recreate the container with the new flags. Checkpodman inspect <container> --format '{{json .Config.Cmd}}'to confirm the flags are on the command line (the binary does not log them). - Port already allocated — the assigned port is held in
pg.yamland skipped for later instances; free it withpg addon removefirst, or pick another with--port N. - Remote API unreachable / unexpectedly reachable — on the default
0.0.0.0a failure to reach it is host firewall, not bind address; conversely, if you did not want it reachable,--listen 127.0.0.1 --force.
Known limitations
- VictoriaLogs itself is a bare log backend: pgcli ships a dedicated
vlagentaddon for file/HTTP collection (plus direct HTTP ingestion APIs and third-party collectors, as described above), but configures no third-party shippers and does no alerting (usevlalertseparately). It is the long-term log store you point Grafana (VictoriaLogs datasource) and your shippers at. - No authentication. VictoriaLogs’s API ingests and queries arbitrary logs; the only protection for a
0.0.0.0bind is the network boundary. This is the same posture as VictoriaMetrics — do not expose it on an untrusted network. - pgcli does not validate
--extra-argvalues (there is no pre-flight check at install). A bad flag surfaces only in the container logs on startup. - On macOS the container runs inside the podman machine; it has been validated on Linux only.