Skip to content

VictoriaLogs

Run VictoriaLogs, the log database of the VictoriaMetrics family, as a managed container.

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.1 for 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-net bridge 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

pg addon install victorialogs

The command pulls the image if needed, creates the container, and prints the URL and retention:

✓ VictoriaLogs installed: "vl"
  Container:  pgcli-victorialogs-default-vl
  Image:      docker.io/victoriametrics/victoria-logs:v1.53.0
  Data:       /home/you/.pgcli/addon/victorialogs/vl/data
  Retention:  binary default (--retention to change)
  URL:        http://0.0.0.0:9428/

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:

# ingest a JSON Lines log entry (the JSON content type is REQUIRED —
# without it VictoriaLogs answers 200 but silently drops the payload)
echo '{"_msg":"hello from pgcli","app":"demo"}' | \
  curl -s -X POST -H 'Content-Type: application/json' \
    http://127.0.0.1:9428/insert/jsonline --data-binary @-

# query with LogsQL
curl -s http://127.0.0.1:9428/select/logsql/query \
  --data-urlencode 'query=app:demo' --data-urlencode 'limit=10'

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:

http://<host>:<port>/select/vmui/

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/query response), and Live (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):

curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"_msg":"hello from pgcli","app":"demo"}' \
  http://127.0.0.1:9428/insert/jsonline

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/.

curl -s http://127.0.0.1:9428/select/logsql/query \
  --data-urlencode 'query=_time:15m level:error' \
  --data-urlencode 'limit=20'

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:word matches the word within that field; field:=value is an exact match and field:~"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, top and 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:

# Relay-only: accept HTTP pushes on :9429 and forward them to VictoriaLogs.
pg addon install vlagent \
  --remote-write-url http://127.0.0.1:9428/insert/native

# Track host files: /var/log/nginx is mounted read-only into the container at
# the same path; --include/--exclude use vlagent's native glob syntax (NOT regex).
pg addon install vlagent \
  --log-path /var/log/nginx \
  --include '/var/log/nginx/**/*.log' \
  --exclude '/var/log/nginx/*.gz' \
  --remote-write-url http://127.0.0.1:9428/insert/native

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-url for 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 -kubernetesCollector and mount the host’s /var/log (plus /var/lib with the Docker runtime so runtime symlinks resolve) via --log-path. It follows /var/log/pods and /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 default hostname and file become 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.

# JSON Lines with explicit field mapping
curl -s -X POST -H 'Content-Type: application/json' \
  --data-binary @app.jsonl \
  'http://127.0.0.1:9428/insert/jsonline?_stream_fields=host,app&_time_field=@timestamp&_msg_field=message'

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):

pg addon install victorialogs --name vl1 \
  --extra-arg -search.maxQueryDuration=60s \
  --extra-arg -memory.allowedPercent=80

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):

podman inspect pgcli-victorialogs-default-vl1 --format '{{json .Config.Cmd}}'

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.

pg addon install victorialogs --name vl2          # second instance: next free port (9429 if 9428 taken)
pg addon install victorialogs --name vl3 --port 9500  # explicit port still takes precedence

Configuration

addons:
  victorialogs:
    vl1:
      name: vl1
      image_tag: docker.io/victoriametrics/victoria-logs:v1.53.0
      host_port: 9428
      listen: 0.0.0.0
      retention: "30d"
      extra_args:
        - -search.maxQueryDuration=60s
        - -memory.allowedPercent=80
      # data_dir: /srv/victorialogs-data      # optional, overrides the default location

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

pg addon list
Web add-ons (victorialogs):
  victorialogs (name: vl1)
    Status:      running
    URL:         http://0.0.0.0:9428/
    Retention:   30d
    Extra args:  -search.maxQueryDuration=60s -memory.allowedPercent=80
    Data:        /home/you/.pgcli/addon/victorialogs/vl1/data
    Image:       docker.io/victoriametrics/victoria-logs:v1.53.0
    Container:   pgcli-victorialogs-default-vl1

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:

pg addon stop victorialogs
pg addon start victorialogs

Autostart on boot

pg autostart enable --victorialogs --name vl

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

pg addon remove victorialogs              # keeps the log storage — stored logs survive a reinstall
pg addon remove victorialogs --clean-data # deletes the log storage too

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 /metrics stays 0). Add the header, or use an ingestion client that sets it.
  • A query returns no data — confirm VictoriaLogs is running (pg addon list shows running), 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). Check podman logs <container> for ingestion errors.
  • Install fails with “container already exists” — the container name is derived from --name and the namespace; use --force to recreate, or pg addon remove first to clean up a partial install.
  • Extra args didn’t take effect — --extra-arg is applied at container creation time, not runtime. Reinstall with --force to recreate the container with the new flags. Check podman 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.yaml and skipped for later instances; free it with pg addon remove first, or pick another with --port N.
  • Remote API unreachable / unexpectedly reachable — on the default 0.0.0.0 a 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 vlagent addon 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 (use vlalert separately). 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.0 bind is the network boundary. This is the same posture as VictoriaMetrics — do not expose it on an untrusted network.
  • pgcli does not validate --extra-arg values (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.