Ship Docker container logs to UptimeEye

On a Docker host you have two options. A single Vector container reads every container's output from the Docker socket and needs no change to your Compose files. Alternatively, Docker's Loki logging driver ships a container's output directly — useful when you only want a few containers.

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

1.Option A: one Vector container for the whole host

Vector's docker_logs source tails every container (new ones included) and knows the container name, image and labels.

vector.yaml
sources:
  docker:
    type: docker_logs
    exclude_containers: [vector]
transforms:
  enrich:
    type: remap
    inputs: [docker]
    source: |
      .service = .container_name
      .image   = .image
      .host    = get_hostname!()
      .env     = "prod"
      parsed, err = parse_json(string!(.message))
      if err == null { . = merge(., parsed) }
      del(.label); del(.source_type); del(.stream)
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 ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    query:
      _msg_field: message
      _time_field: timestamp
      _stream_fields: service,host,env
Note: The key lives in vector.yaml itself — keep the file readable by root only (chmod 600). Vector does not expand ${ENV} placeholders in its config; to keep the key in a separate file use its secret backend as shown on the Kubernetes and Vector pages.

2.Run it next to your services

docker-compose.yml
services:
  vector:
    image: timberio/vector:0.49.0-alpine
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./vector.yaml:/etc/vector/vector.yaml:ro
      - vector-data:/var/lib/vector
volumes:
  vector-data:

3.Option B: the Loki logging driver per container

Docker's Loki driver speaks the Loki push protocol, which UptimeEye accepts. The key goes into the URL as basic-auth password; labels become fields.

shell
docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions

docker run -d --name api \
  --log-driver=loki \
  --log-opt loki-url="https://key:ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@logs.uptimeeye.com/v1/ingest/loki/api/v1/push" \
  --log-opt loki-external-labels="service=api,env=prod" \
  --log-opt loki-batch-wait=2s \
  my-org/api:latest
Note: In Compose, put the same options under logging: { driver: loki, options: { … } }.

4.Search

Every container shows up as service:=<container name>. Add level:error or click a value in the fields panel to narrow down.

Fields you get

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

  • service (container name)
  • image
  • host
  • env
  • JSON fields your application logs

Tips

  • Option A keeps working when containers restart or are recreated; the Loki driver only covers containers you started with it.
  • Applications that log plain text keep the whole line as the message; timestamps and levels are still searchable via the time range and word search.

FAQ

Can I ship only some containers with Vector?
Yes — include_containers / exclude_containers on the docker_logs source, or include_labels to select by Compose label.
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.