520 Iocage plugin ansible-syslogng

Use case

Configure and run a log server. Configure log clients and test them. Use syslog-ng. Clone the iocage plugin ansible-syslogng. The project keys are jail’s aliases.

project:
  logserv:
    class: [logserv]
    plugin: ansible-syslogng
    vmm: iocage_05
  foo:
    class: [logclient]
    plugin: ansible-syslogng
    vmm: iocage_05
  bar:
    class: [logclient]
    plugin: ansible-syslogng
    vmm: iocage_05
  • Destroy all jails

    (env) > ansible-playbook vbotka.freebsd.pb_iocage_destroy_all_jails.yml \
                             -i iocage.ini \
                             --flush-cache
    
  • Fetch the required iocage plugins

    (env) > ansible-playbook vbotka.freebsd.pb_iocage_plugins.yml \
                             -i iocage.ini \
                             -t project_plugins \
                             --flush-cache
    
  • Create the project

    (env) > ansible-playbook vbotka.freebsd.pb_iocage_project_create_from_plugins.yml \
                             -i iocage.ini \
                             -i hosts \
                             --flush-cache
    
  • Configure log server

    (env) > ansible-playbook pb-logserv.yml -i hosts
    
  • Configure log clients

    (env) > ansible-playbook pb-logclient.yml -i hosts -i iocage.ini
    
  • Test

    (env) > ansible-playbook pb-test-logclient.yml -i hosts
    

Tree

shell > tree .
.
├── ansible.cfg
├── group_vars
│   ├── all
│   │   ├── common.yml
│   │   └── project.yml
│   ├── logclient_group
│   │   └── syslog-ng-client.yml
│   └── logserv_group
│       └── syslog-ng-server.yml
├── hosts
│   └── 05_iocage.yml
├── host_vars
│   └── iocage_05
│       └── iocage.yml
├── iocage.ini
├── pb-all-groups.yml
├── pb-logclient.yml
├── pb-logserv.yml
├── pb-test-logclient.yml
└── pb-test-logserv.yml

Synopsis

Requirements

Notes

  • Quoting syslog-ng - FreeBSD Wiki:

    One of the most typical use of syslog-ng is central log aggregation. … It collects log messages on TCP port 514 and saves them to directories and files based on sender host name and current date.

Note

The same syslog-ng configuration is used in 521 Iocage plugins ansible-pull-syslogng-*

ansible.cfg

[defaults]
callback_result_format = yaml
deprecation_warnings = false
display_skipped_hosts = false
gathering = explicit
host_key_checking = false

[connection]
pipelining = true

Inventory iocage.ini

iocage_05

[iocage]
iocage_05

[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent

hosts

hosts/05_iocage.yml
plugin: vbotka.freebsd.iocage
host: iocage_05
user: admin
sudo: true
get_properties: true
inventory_hostname_tag: alias
# cache
cache: true
cache_plugin: ansible.builtin.jsonfile
cache_connection: /var/tmp/inventory_cache
cache_timeout: 3600
cache_prefix: iocage_05_

compose:
  iocage_tags: dict(iocage_properties.notes | regex_findall('(\w+)=([\w\-]+)'))
  iocage_classes: iocage_properties.notes | regex_findall('class=(\w+)')
# connection plugin vbotka.freebsd.jailexec
  ansible_connection: "'vbotka.freebsd.jailexec'"
  ansible_jail_host: dict(iocage_properties.notes | regex_findall('(\w+)=([\w\-]+)')).vmm | d('none')
  ansible_jail_name: iocage_jid
  ansible_jail_privilege_escalation: "'sudo'"
# ansible options
  ansible_python_interpreter: "'auto_silent'"

groups:
  logserv_group: iocage_classes is contains('logserv')
  logclient_group: iocage_classes is contains('logclient')

keyed_groups:
  - prefix: state
    key: iocage_state
  - prefix: vmm
    key: iocage_tags.vmm

Note

The below group declarations

logserv: iocage_classes is contains('logserv')
logclient: iocage_classes is contains('logclient')

fail (ansible version 2.20)

Failed to parse inventory with 'auto' plugin.

<<< caused by >>>

can't add group to itself

As a workaround, use these declarations:

logserv_group: iocage_classes is contains('logserv')
logclient_group: iocage_classes is contains('logclient')

group_vars

group_vars/all/common.yml
ansible_python_interpreter: auto_silent
log_serv: "{{ hostvars.logserv.iocage_ip4 }}"
group_vars/all/project.yml
# The project keys are jails aliases.
project:
  logserv:
    class: [logserv]
    plugin: ansible-syslogng
    vmm: iocage_05
  foo:
    class: [logclient]
    plugin: ansible-syslogng
    vmm: iocage_05
  bar:
    class: [logclient]
    plugin: ansible-syslogng
    vmm: iocage_05

plugins:
  ansible-syslogng:
    git: https://github.com/vbotka/iocage-plugins-devel
    branch: main
    properties:
      bpf: 1
      dhcp: 1
      vnet: 1
      boot: 0

# Jail properties.
properties:
  bpf: 1
  dhcp: 1
  vnet: 1
  type: jail
  boot: 1

# Declare vmm. Dictionary of iocage hosts.
vmm_groups: "{{ dict(project | dict2items | groupby('value.vmm')) }}"
vmm: "{{ dict(vmm_groups.keys() | zip(vmm_groups.values() | map('items2dict'))) }}"
group_vars/logserv_group/syslog-ng-server.yml
fp_syslogd: true
fp_syslogd_enable: false
fp_syslogd_conf_sanity: false

fp_syslogng: true
fp_syslogng_enable: true
fp_syslogng_conf_template: syslog-ng.conf.j2
fp_syslogng_conf:
  header:
    - '@version:4.8'
    - '@include "scl.conf"'
  options:
    - threaded(yes)
    - group("wheel")
    - perm(0640)
  source:
    s_system:
      - unix-dgram("/var/run/log")
      - unix-dgram("/var/run/logpriv" perm(0600))
      - internal()
    s_ansible:
      - file("/var/log/ansible.log" follow-freq(1) program-override("ansible"))
    s_remote:
      - tcp(port(514))
  destination:
    d_local:
      - file("/var/log/remote/${HOST}/${YEAR}_${MONTH}_${DAY}.log" create-dirs(yes))
  filter:
    f_messages:
      - level(notice..emerg) and not facility(auth, authpriv, lpr, mail, news)
    f_daemon:
      - facility(daemon)
  log:
    - source: s_remote
      destination: d_local
    - source: s_system
      filter: f_daemon
      destination: d_local
    - source: s_system
      filter: f_messages
      destination: d_local
    - source: s_ansible
      destination: d_local

Note

The same configuration from the repo ansible-conf-syslogng-server is used in 521 Iocage plugins ansible-pull-syslogng-*

group_vars/logclient_group/syslog-ng-client.yml
fp_syslogd: true
fp_syslogd_enable: false
fp_syslogd_conf_sanity: false

fp_syslogng: true
fp_syslogng_enable: true
fp_syslogng_conf_template: syslog-ng.conf.j2
fp_syslogng_conf:
  header:
    - '@version:4.8'
    - '@include "scl.conf"'
  options:
    - threaded(yes)
    - group("wheel")
    - perm(0640)
  source:
    s_system:
      - unix-dgram("/var/run/log")
      - unix-dgram("/var/run/logpriv" perm(0600))
      - internal()
    s_ansible:
      - file("/var/log/ansible.log" follow-freq(1) program-override("ansible"))
  destination:
    d_network:
      - network("{{ log_serv }}" port(514) transport("tcp"))
  filter:
    f_messages:
      - level(info..emerg) and not facility(auth, authpriv, lpr, mail, news)
    f_daemon:
      - facility(daemon)
  log:
    - source: s_system
      filter: f_daemon
      destination: d_network
    - source: s_system
      filter: f_messages
      destination: d_network
    - source: s_ansible
      destination: d_network

Note

The same configuration from the repo ansible-conf-syslogng-client is used in 521 Iocage plugins ansible-pull-syslogng-*

host_vars

host_vars/iocage_05/iocage.yml
# Add iocage_05 host specific varaiables here.

Playbook output - Fetch the iocage plugin

(env) > ansible-playbook vbotka.freebsd.pb_iocage_plugins.yml \
                         -i iocage.ini \
                         -t project_plugins \
                         -e debug=true
PLAY [Fetch and stop iocage plugins.] ******************************************

TASK [One tag is required.] ****************************************************
ok: [iocage_05]

TASK [Test the tag is known.] **************************************************
ok: [iocage_05]

TASK [Get already fetched plugins.] ********************************************
ok: [iocage_05]

TASK [Debug fetched plugins debug=true] ****************************************
ok: [iocage_05] => 
    msg: |-
        iocage_plugins:
          ansible-zero:
              boot: 'off'
              doc_url: '-'
              ip4: '-'
              ip4_dict:
                  ip4: []
                  msg: DHCP (not running)
              ip6: '-'
              jid: None
              portal: '-'
              release: 15.0-RELEASE
              state: down
              template: '-'
              type: pluginv2

        plugins:
          ansible-syslogng:
              branch: main
              git: https://github.com/vbotka/iocage-plugins-devel
              properties:
                  boot: 0
                  bpf: 1
                  dhcp: 1
                  vnet: 1

TASK [Debug required plugins debug=true] ***************************************
ok: [iocage_05] => 
    msg: |-
        required_plugins:
          - ansible-syslogng

        selected_plugins:
          -   key: ansible-syslogng
            value:
                branch: main
                git: https://github.com/vbotka/iocage-plugins-devel
                properties:
                    boot: 0
                    bpf: 1
                    dhcp: 1
                    vnet: 1

        project_vmm:
          iocage_05: [ansible-syslogng]

TASK [Check all required plugins are included in the dictionary plugins.] ******
ok: [iocage_05]

TASK [Debug commands debug=true] ***********************************************
ok: [iocage_05] => (item=ansible-syslogng) => 
    msg: |-
        iocage fetch --plugin-name ansible-syslogng --git_repository https://github.com/vbotka/iocage-plugins-devel --branch main boot=0 bpf=1 dhcp=1 vnet=1

TASK [Fetch required plugins.] *************************************************
ok: [iocage_05] => (item=ansible-syslogng)

TASK [Stop fetched plugins.] ***************************************************
ok: [iocage_05]

PLAY RECAP *********************************************************************
iocage_05                  : ok=9    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

List plugins

shell > ssh admin@iocage_05 sudo iocage list -P
+------+------------------+------+-------+----------+--------------+--------------------+-----+----------+--------+---------+
| JID  |       NAME       | BOOT | STATE |   TYPE   |   RELEASE    |        IP4         | IP6 | TEMPLATE | PORTAL | DOC_URL |
+======+==================+======+=======+==========+==============+====================+=====+==========+========+=========+
| None | ansible-syslogng | off  | down  | pluginv2 | 15.0-RELEASE | DHCP (not running) | -   | -        | -      | -       |
+------+------------------+------+-------+----------+--------------+--------------------+-----+----------+--------+---------+
| None | ansible-zero     | off  | down  | pluginv2 | 15.0-RELEASE | DHCP (not running) | -   | -        | -      | -       |
+------+------------------+------+-------+----------+--------------+--------------------+-----+----------+--------+---------+

Playbook output - Create project from iocage plugins

Flush the cache if you created the project and haven’t refreshed the inventory cache yet.

(env) > ansible-playbook vbotka.freebsd.pb_iocage_project_create_from_plugins.yml \
                         -i iocage.ini \
                         -i hosts \
                         --flush-cache
PLAY [Create and start project jails from iocage plugins.] *********************

TASK [Clone jails from plugins.] ***********************************************
ok: [iocage_05] => (item=logserv)
ok: [iocage_05] => (item=foo)
ok: [iocage_05] => (item=bar)

PLAY RECAP *********************************************************************
iocage_05                  : ok=1    changed=0    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0   

Playbook pb-all-groups.yml

- name: Display all groups.
  hosts: all

  tasks:

    - debug:
        msg: |
          ansible_host: {{ ansible_host | d('UNDEFINED') }}
          iocage_properties.host_hostname: {{ iocage_properties.host_hostname | d('UNDEFINED') }}
          iocage_properties.host_hostuuid: {{ iocage_properties.host_hostuuid | d('UNDEFINED') }}
          iocage_jid: {{ iocage_jid }}
          iocage_classes: {{ iocage_classes | d([]) | to_yaml }}
          iocage_tags: {{ iocage_tags | d({}) | to_yaml }}

    - debug:
        msg: |
          {% for group in groups %}
          {{ group }}: {{ groups[group] }}
          {% endfor %}
      run_once: true

Playbook output - Display groups

Flush the cache if necessary.

(env) > ansible-playbook pb-all-groups.yml -i hosts --flush-cache
PLAY [Display all groups.] *****************************************************

TASK [debug] *******************************************************************
ok: [ansible-syslogng] => 
    msg: |-
        ansible_host: ansible-syslogng
        iocage_properties.host_hostname: ansible-syslogng
        iocage_properties.host_hostuuid: ansible-syslogng
        iocage_jid: None
        iocage_classes: []

        iocage_tags: {}
ok: [ansible-zero] => 
    msg: |-
        ansible_host: ansible-zero
        iocage_properties.host_hostname: ansible-zero
        iocage_properties.host_hostuuid: ansible-zero
        iocage_jid: None
        iocage_classes: []

        iocage_tags: {}
ok: [bar] => 
    msg: |-
        ansible_host: bar
        iocage_properties.host_hostname: aa3977f7-1efb-42d7-ba12-dd6dac8d4cfa
        iocage_properties.host_hostuuid: aa3977f7-1efb-42d7-ba12-dd6dac8d4cfa
        iocage_jid: 72
        iocage_classes: [logclient]

        iocage_tags: {alias: bar, class: logclient, vmm: iocage_05}
ok: [foo] => 
    msg: |-
        ansible_host: foo
        iocage_properties.host_hostname: c6b535de-791d-4ede-ba24-3b82389e6484
        iocage_properties.host_hostuuid: c6b535de-791d-4ede-ba24-3b82389e6484
        iocage_jid: 71
        iocage_classes: [logclient]

        iocage_tags: {alias: foo, class: logclient, vmm: iocage_05}
ok: [logserv] => 
    msg: |-
        ansible_host: logserv
        iocage_properties.host_hostname: e8778af5-b480-4f23-91d4-be3d0caffc26
        iocage_properties.host_hostuuid: e8778af5-b480-4f23-91d4-be3d0caffc26
        iocage_jid: 70
        iocage_classes: [logserv]

        iocage_tags: {alias: logserv, class: logserv, vmm: iocage_05}

TASK [debug] *******************************************************************
ok: [ansible-syslogng] => 
    msg: |-
        all: ['ansible-syslogng', 'ansible-zero', 'bar', 'foo', 'logserv']
        ungrouped: []
        state_down: ['ansible-syslogng', 'ansible-zero']
        logclient_group: ['bar', 'foo']
        state_up: ['bar', 'foo', 'logserv']
        vmm_iocage_05: ['bar', 'foo', 'logserv']
        logserv_group: ['logserv']

PLAY RECAP *********************************************************************
ansible-syslogng           : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
ansible-zero               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
bar                        : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
foo                        : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
logserv                    : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Playbook pb-logserv.yml

- name: Configure and start Log Server.
  hosts: logserv_group
    
  tasks:

    - name: Custom facts.
      when: custom_facts | d(true) | bool
      block:

        - name: Get custom facts
          ansible.builtin.setup:
            filter: ansible_local

        - debug:
            var: ansible_local

    - name: Install syslog-ng
      when: install | d(false) | bool
      community.general.pkgng:
        name: sysutils/syslog-ng
        use_globs: false

    - name: Configure and start Log Server.
      ansible.builtin.import_role:
        name: vbotka.freebsd.postinstall
        tasks_from: syslog-ng.yml

Playbook output - Configure and start Log Server

(env) > ansible-playbook pb-logserv.yml -i hosts
PLAY [Configure and start Log Server.] *****************************************

TASK [Get custom facts] ********************************************************
ok: [logserv]

TASK [debug] *******************************************************************
ok: [logserv] => 
    ansible_local:
        iocage:
            iocage_plugin_name: ansible-syslogng

TASK [vbotka.freebsd.postinstall : Syslog-ng: Sanity fp_syslogng_conf is empty.] ***
ok: [logserv]

TASK [vbotka.freebsd.postinstall : Syslog-ng: Configure /usr/local/etc/syslog-ng.conf] ***
ok: [logserv]

TASK [vbotka.freebsd.postinstall : Rcconf: Configure syslog_ng_enable in /etc/rc.conf] ***
ok: [logserv]

PLAY RECAP *********************************************************************
logserv                    : ok=5    changed=0    unreachable=0    failed=0    skipped=8    rescued=0    ignored=0   

Playbook pb-test-logserv.yml

- name: Test Log Server.
  hosts: logserv_group
    
  tasks:

    - name: Run commands
      register: out
      ansible.builtin.shell: "{{ item }}"
      loop:
        - rm -rf /var/log/remote/localhost/*
        - service syslog-ng status
        - loggen -i -S -n 1 localhost 514
        - sleep 2; find /var/log/remote/localhost/ -name *.log | xargs cat

    - name: Debug.
      when: debug | d(false) | bool
      ansible.builtin.debug:
        msg: |
          {% for i in out.results %}
          shell> {{ i.item }}
          {% if i.stdout | length > 0 %}
          {{ i.stdout }}
          {% endif %}
          {% if i.stderr | length > 0 %}
          {{ i.stderr }}
          {% endif %}

          {% endfor %}

Playbook output - Test Log Server

(env) > ansible-playbook pb-test-logserv.yml -i hosts -e debug=true
PLAY [Test Log Server.] ********************************************************

TASK [Run commands] ************************************************************
changed: [logserv] => (item=rm -rf /var/log/remote/localhost/*)
changed: [logserv] => (item=service syslog-ng status)
changed: [logserv] => (item=loggen -i -S -n 1 localhost 514)
changed: [logserv] => (item=sleep 2; find /var/log/remote/localhost/ -name *.log | xargs cat)

TASK [Debug.] ******************************************************************
ok: [logserv] => 
    msg: |-
        shell> rm -rf /var/log/remote/localhost/*

        shell> service syslog-ng status
        syslog_ng is running as pid 60382.

        shell> loggen -i -S -n 1 localhost 514
        count=1, rate = 26315.79 msg/sec
        average rate = 2.00 msg/sec, count=1, time=0.50039, (average) msg size=256, bandwidth=0.50 kB/sec

        shell> sleep 2; find /var/log/remote/localhost/ -name *.log | xargs cat

PLAY RECAP *********************************************************************
logserv                    : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Playbook pb-logclient.yml

- name: Configure and start Log Client.
  hosts: logclient_group
    
  tasks:

    - name: Custom facts.
      when: custom_facts | d(true) | bool
      block:

        - name: Get custom facts
          ansible.builtin.setup:
            filter: ansible_local

        - debug:
            var: ansible_local
    
    - name: Debug.
      when: debug | d(false) | bool
      ansible.builtin.debug:
        msg: |
          log_serv: {{ log_serv }}
          fp_syslogd_enable: {{ fp_syslogd_enable }}
          fp_syslogng_enable: {{ fp_syslogng_enable }}

    - name: Install syslog-ng
      when: install | d(false) | bool
      delegate_to: "{{ iocage_tags.vmm }}"
      community.general.pkgng:
        name: sysutils/syslog-ng
        use_globs: false
        jail: "{{ iocage_jid }}"
        cached: true

    - name: Stop syslogd.
      vbotka.freebsd.service:
        script: syslogd
        command: stop

    - name: Disable syslogd.
      vbotka.freebsd.service:
        script: syslogd
        command: disable

    - name: Configure and start syslog-ng.
      ansible.builtin.import_role:
        name: vbotka.freebsd.postinstall
        tasks_from: syslog-ng.yml

Playbook output - Configure and start Log Client

(env) > ansible-playbook pb-logclient.yml -i hosts -i iocage.ini -e debug=true
PLAY [Configure and start Log Client.] *****************************************

TASK [Get custom facts] ********************************************************
ok: [bar]
ok: [foo]

TASK [debug] *******************************************************************
ok: [foo] => 
    ansible_local:
        iocage:
            iocage_plugin_name: ansible-syslogng
ok: [bar] => 
    ansible_local:
        iocage:
            iocage_plugin_name: ansible-syslogng

TASK [Debug.] ******************************************************************
ok: [bar] => 
    msg: |-
        log_serv: 10.10.99.143
        fp_syslogd_enable: False
        fp_syslogng_enable: True
ok: [foo] => 
    msg: |-
        log_serv: 10.10.99.143
        fp_syslogd_enable: False
        fp_syslogng_enable: True

TASK [Stop syslogd.] ***********************************************************
ok: [bar]
ok: [foo]

TASK [Disable syslogd.] ********************************************************
ok: [bar]
ok: [foo]

TASK [vbotka.freebsd.postinstall : Syslog-ng: Sanity fp_syslogng_conf is empty.] ***
ok: [bar]
ok: [foo]

TASK [vbotka.freebsd.postinstall : Syslog-ng: Configure /usr/local/etc/syslog-ng.conf] ***
changed: [foo]
changed: [bar]

TASK [vbotka.freebsd.postinstall : Rcconf: Configure syslog_ng_enable in /etc/rc.conf] ***
ok: [foo]
ok: [bar]

RUNNING HANDLER [vbotka.freebsd.postinstall : Reload syslog-ng] ****************
ok: [foo]
ok: [bar]

PLAY RECAP *********************************************************************
bar                        : ok=9    changed=1    unreachable=0    failed=0    skipped=8    rescued=0    ignored=0   
foo                        : ok=9    changed=1    unreachable=0    failed=0    skipped=8    rescued=0    ignored=0   

List jails

shell > ssh admin@iocage_05 sudo iocage list -l
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+------------------+----------+
| JID  |                 NAME                 | BOOT | STATE |   TYPE   |   RELEASE    |         IP4          | IP6 |     TEMPLATE     | BASEJAIL |
+======+======================================+======+=======+==========+==============+======================+=====+==================+==========+
| 72   | aa3977f7-1efb-42d7-ba12-dd6dac8d4cfa | on   | up    | jail     | 15.0-RELEASE | epair0b|10.10.99.126 | -   | ansible-syslogng | yes      |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+------------------+----------+
| None | ansible-syslogng                     | off  | down  | pluginv2 | 15.0-RELEASE | DHCP (not running)   | -   | -                | yes      |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+------------------+----------+
| None | ansible-zero                         | off  | down  | pluginv2 | 15.0-RELEASE | DHCP (not running)   | -   | -                | yes      |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+------------------+----------+
| 71   | c6b535de-791d-4ede-ba24-3b82389e6484 | on   | up    | jail     | 15.0-RELEASE | epair0b|10.10.99.200 | -   | ansible-syslogng | yes      |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+------------------+----------+
| 70   | e8778af5-b480-4f23-91d4-be3d0caffc26 | on   | up    | jail     | 15.0-RELEASE | epair0b|10.10.99.143 | -   | ansible-syslogng | yes      |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+------------------+----------+

Playbook pb-test-logclient.yml

- name: Test Log Client.
  hosts: logclient_group

  tasks:

    - name: Run loggen
      register: out
      ansible.builtin.command: "loggen -i -S -n 1 {{ log_serv }} 514"

    - name: Debug.
      ansible.builtin.debug:
        var: out.stderr

- name: Display the logs.
  hosts: logserv_group
    
  tasks:

    - name: Get log files paths.
      register: out
      ansible.builtin.find:
        paths: /var/log/remote
        recurse: true
        patterns: '*.log'

    - name: Get log files.
      register: out
      ansible.builtin.command: "cat {{ item }}"
      loop: "{{ out.files | map(attribute='path') }}"

    - name: Display log files.
      ansible.builtin.debug:
        msg: |
          {{ item.stdout }}

          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      loop: "{{ out.results }}"
      loop_control:
        label: "{{ item.cmd }}"

Playbook output - Test Log Client

(env) > ansible-playbook pb-test-logclient.yml -i hosts
PLAY [Test Log Client.] ********************************************************

TASK [Run loggen] **************************************************************
changed: [bar]
changed: [foo]

TASK [Debug.] ******************************************************************
ok: [bar] => 
    out.stderr: |-
        count=1, rate = 27027.03 msg/sec
        average rate = 2.00 msg/sec, count=1, time=0.500308, (average) msg size=256, bandwidth=0.50 kB/sec
ok: [foo] => 
    out.stderr: |-
        count=1, rate = 30303.03 msg/sec
        average rate = 2.00 msg/sec, count=1, time=0.500339, (average) msg size=256, bandwidth=0.50 kB/sec

PLAY [Display the logs.] *******************************************************

TASK [Get log files paths.] ****************************************************
ok: [logserv]

TASK [Get log files.] **********************************************************
changed: [logserv] => (item=/var/log/remote/10.10.99.126/2026_05_13.log)
changed: [logserv] => (item=/var/log/remote/10.10.99.200/2026_05_13.log)

TASK [Display log files.] ******************************************************
ok: [logserv] => (item=['cat', '/var/log/remote/10.10.99.126/2026_05_13.log']) => 
    msg: |-
        May 13 13:20:04 10.10.99.126 syslog-ng[62336]: Loading the new configuration;
        May 13 13:20:04 10.10.99.126 syslog-ng[62336]: Configuration reload finished;
        May 13 13:20:04 10.10.99.126 syslog-ng[62336]: Syslog connection established; fd='20', server='AF_INET(10.10.99.143:514)', local='AF_INET(0.0.0.0:0)'
        May 13 13:20:07 10.10.99.126 1 2026-05-13T13:20:07.254815+02:00 aa3977f7-1efb-42d7-ba12-dd6dac8d4cfa ansible-ansible.legacy.command 63708 - - Invoked with _raw_params=loggen -i -S -n 1 10.10.99.143 514 _uses_shell=False expand_argument_vars=True stdin_add_newline=True strip_empty_ends=True cmd=None argv=None chdir=None executable=None creates=None removes=None stdin=None
        May 13 13:20:07 10.10.99.126 prg00000[1234]: seq: 0000000000, thread: 0000, runid: 1778671207, stamp: 2026-05-13T13:20:07 PADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADD

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ok: [logserv] => (item=['cat', '/var/log/remote/10.10.99.200/2026_05_13.log']) => 
    msg: |-
        May 13 13:20:04 10.10.99.200 syslog-ng[61359]: Loading the new configuration;
        May 13 13:20:04 10.10.99.200 syslog-ng[61359]: Configuration reload finished;
        May 13 13:20:04 10.10.99.200 syslog-ng[61359]: Syslog connection established; fd='20', server='AF_INET(10.10.99.143:514)', local='AF_INET(0.0.0.0:0)'
        May 13 13:20:07 10.10.99.200 1 2026-05-13T13:20:07.261130+02:00 c6b535de-791d-4ede-ba24-3b82389e6484 ansible-ansible.legacy.command 63709 - - Invoked with _raw_params=loggen -i -S -n 1 10.10.99.143 514 _uses_shell=False expand_argument_vars=True stdin_add_newline=True strip_empty_ends=True cmd=None argv=None chdir=None executable=None creates=None removes=None stdin=None
        May 13 13:20:07 10.10.99.200 prg00000[1234]: seq: 0000000000, thread: 0000, runid: 1778671207, stamp: 2026-05-13T13:20:07 PADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADD

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

PLAY RECAP *********************************************************************
bar                        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
foo                        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
logserv                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0