# Filebeat: container logs + our own systemd units -> Elasticsearch. # Autodiscover picks up every container, and add_docker_metadata brings the vanguard.service / # vanguard.category labels with it (Beats turn the dots into underscores), so filtering by category in Kibana # needs no parsing. See LOGGING.md for what each service's lines look like. # # NOTE (9.x): the old "container" input is GONE, not merely deprecated — Filebeat 9 refuses the config and # logs "Container input is deprecated. Use Filestream input with its container parser instead", leaving the # process up with zero harvesters. Container logs are read by filestream + the container parser, and every # filestream input needs its own stable id. filebeat.autodiscover: providers: - type: docker hints.enabled: false templates: - condition: ~ # every container config: - type: filestream id: container-${data.docker.container.id} paths: ["/var/lib/docker/containers/${data.docker.container.id}/*.log"] parsers: - container: ~ prospector.scanner.symlinks: true # Stamp the id here rather than letting add_docker_metadata guess it from the path. processors: - add_fields: target: container fields: id: "${data.docker.container.id}" name: "${data.docker.container.name}" image.name: "${data.docker.container.image}" filebeat.inputs: - type: journald id: vanguard-units include_matches: match: - "_SYSTEMD_UNIT=dumpd.service" - "_SYSTEMD_UNIT=normalize-sweep.service" - "_SYSTEMD_UNIT=trash-purge.service" - "_SYSTEMD_UNIT=vgdeband.service" - "_SYSTEMD_UNIT=vanguard-deadman.service" processors: - add_docker_metadata: match_fields: ["container.id"] # the id the autodiscover template stamped above - add_host_metadata: ~ # promote our labels to real fields so Kibana filters on service.name and vanguard.category - copy_fields: fields: - from: container.labels.vanguard_service to: service.name - from: container.labels.vanguard_category to: vanguard.category fail_on_error: false ignore_missing: true # The Observability overview's "Logs rate" chart groups by event.dataset, so anything without one lands in # a single "unknown" bucket and the chart says nothing. Give every line a dataset: the container's # vanguard.service label, or the systemd unit for journald lines. copy_fields does not overwrite a target # that already exists, so the first rule that matches wins and the other is skipped. - copy_fields: fields: - from: container.labels.vanguard_service to: event.dataset - from: systemd.unit to: event.dataset fail_on_error: false ignore_missing: true - drop_fields: fields: ["agent.ephemeral_id", "ecs.version", "log.offset"] ignore_missing: true output.elasticsearch: hosts: ["http://elasticsearch:9200"] # Elasticsearch requires authentication now (see observability/kibana.yml for why security is on). These # come from the container environment, which compose fills from .env — no secret is committed here. username: "${ES_BEATS_USER}" password: "${ES_BEATS_PASSWORD}" setup.kibana: # no credentials: Kibana's anonymous provider signs these in host: "http://kibana:5601" setup.ilm.enabled: true # retention: set the delete phase once in Kibana (README 5h) # Single node: a replica has nowhere to go, so every beats index would sit unassigned and hold the # cluster at yellow forever. Zero replicas is the correct setting here, not a workaround. setup.template.overwrite: true setup.template.settings: index.number_of_replicas: 0 logging.level: info