Ship logs with Vector to UptimeEye

Vector is a single binary that reads from many sources, transforms events with VRL and ships them reliably. UptimeEye accepts Vector's elasticsearch sink (bulk protocol) — the configuration below is the template every Vector guide on this site builds on.

Endpoint: https://logs.uptimeeye.com/v1/ingest/elasticsearch/_bulk

1.Install

shell
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev | bash
# or: apt/yum packages and Docker images at vector.dev/docs/setup/installation/

2.Files and the systemd journal

/etc/vector/vector.yaml
# The ingest key is read from /etc/vector/secrets/key through Vector's
# secret backend; ${ENV} placeholders are not expanded in the config.
secret:
  local:
    type: directory
    path: /etc/vector/secrets

sources:
  app_files:
    type: file
    include: [/var/log/myapp/*.log]
    ignore_older_secs: 86400
  journal:
    type: journald
    include_units: [nginx.service, postgresql.service]

transforms:
  enrich:
    type: remap
    inputs: [app_files, journal]
    source: |
      .host = get_hostname!()
      .env  = "prod"
      # files: service from the path; journald: from the unit
      if exists(.file) { .service = replace(basename!(string!(.file)), r'\.log$', "") }
      if exists(._SYSTEMD_UNIT) { .service = replace(string!(._SYSTEMD_UNIT), ".service", "") }
      parsed, err = parse_json(string!(.message))
      if err == null { . = merge(., parsed) }

sinks:
  uptimeeye:
    type: elasticsearch
    inputs: [enrich]
    endpoints: ["https://logs.uptimeeye.com/v1/ingest/elasticsearch/"]
    api_version: v8
    compression: gzip
    healthcheck: { enabled: false }
    request:
      headers:
        Authorization: "Bearer SECRET[local.key]"
    query:
      _msg_field: message
      _time_field: timestamp
      _stream_fields: service,host,env
    buffer:
      type: disk
      max_size: 268435488
      when_full: block

3.Run and verify

shell
install -d -m 700 -o vector /etc/vector/secrets
printf '%s' 'ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' > /etc/vector/secrets/key
chown vector /etc/vector/secrets/key && chmod 600 /etc/vector/secrets/key
vector validate /etc/vector/vector.yaml
systemctl enable --now vector
vector top   # live view of events per component

Fields you get

These show up in the fields panel and can be used in every filter:

  • service
  • host
  • env
  • file for file sources
  • journald metadata such as _SYSTEMD_UNIT, PRIORITY

Tips

  • Stack traces: use the multiline option of the file source (multiline: { start_pattern: '^\\d{4}-\\d{2}-\\d{2}', mode: halt_before, condition_pattern: '^\\d{4}-\\d{2}-\\d{2}', timeout_ms: 1000 }).
  • Drop noise before it counts against your quota: a filter transform with condition: '.level != "debug"'.
  • Vector's http sink also works: uri: ${H}/v1/ingest/jsonline?_stream_fields=service,env, encoding: { codec: json }, framing: { method: newline_delimited }, auth: { strategy: bearer, token: … }.

FAQ

Why the elasticsearch sink and not http?
Both work. The Elasticsearch bulk protocol gives Vector per-line acknowledgements and back-pressure for free; the http sink is a fine alternative if you prefer JSON lines.
Where do I get the ingest key?
In the app under API Keys → New API Key → type “Log ingest”. The key starts with ue_ingest_ and is shown once. Management keys (ue_live_) are refused by the ingest endpoint.
How do I check that logs arrive?
Open Logs in the app, pick the 15m range and search for service:=<your service>. New lines are searchable within about a second; Live tail shows them with a ~6 s delay.