Bootstrap FreeKB - Ansible - stdout as JSON or YAML
Ansible - stdout as JSON or YAML

Updated:   |  Ansible articles

Let's say you have the following playbook which will create the /tmp/foo.txt file.

---
- hosts: localhost
  tasks:
  - name: create /tmp/foo.txt
    ansible.builtin.file:
      path: /tmp/foo.txt
      state: touch
...

 

Running this playbook should return something like this. Notice the output is not structured JSON or YAML.

~]$ ansible-playbook testing.yml
PLAY [localhost] 

TASK [Gathering Facts] 
ok: [localhost]

TASK [file] 
changed: [localhost] => (item=touch)

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

 

stdout_callback can be used to configure stdout to be JSON or YAML. You will need to ensure you have the ansible.posix collection installed. If you are not familiar with collections, check out my article on Getting Started with Collections.

The collections_path or collections_paths directive in your ansible.cfg file can be used to specify the directory or directories that Ansible will use for collections.

[defaults]
collections_path = /usr/local/ansible/collections,/usr/local/ansible_testing/collections

 

The ansible-galaxy collection list command can be used to list the collection you have installed in your collections paths.

~]$ ansible-galaxy collection list
# /home/john.doe/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
amazon.aws        6.1.0
community.docker  1.9.0
community.general 4.0.2

# /usr/share/ansible/collections/ansible_collections
Collection               Version
------------------------ -------
redhat.rhel_system_roles 1.0.1

 

Optionally, you can include the path to a specific directory that contains collections you have installed.

~]$ ansible-galaxy collection list --collections-path /path/to/collections
Collection        Version
----------------- -------
amazon.aws        6.1.0
community.docker  1.9.0
community.general 4.0.2

 

If you do not have the ansible.posix collection installed, the ansible-galaxy collection install command can be used to install a collection. By default, this will install the collection to /home/username/.ansible/collections/ansible_collections/.

ansible-galaxy collection install ansible.posix

 

There are a number of ways to configure Ansible to use the stdout callback, where the higher option in this list will take precedence over the lower option.

  1. ANSIBLE_STDOUT_CALLBACK variable
  2. stdout_callback in ansible.cfg in the present working directory
  3. stdout_callback in .ansible.cfg in the user home directory (e.g. /home/john.doe/.ansible.cfg)
  4. stdout_callback in /etc/ansible/ansible.cf

 

ANSIBLE_STDOUT_CALLBACK ​variable

Here is how you could set the stdout callback using the ANSIBLE_STDOUT_CALLBACK variable on a Linux system. Be aware that you would need to issue the export command before issuing the ansible-playbook command.

export ANSIBLE_STDOUT_CALLBACK=ansible.posix.json

 

Or you can include this in your users hidden .bash_profile file (e.g. /home/john.doe/.bash_profile) to make this setting permanent.

~]$ cat /home/john.doe/.bash_profile 
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
export ANSIBLE_STDOUT_CALLBACK=ansible.posix.json

 

Or in a playbook using environment.

---
- hosts: localhost
  environment:
    ANSIBLE_STDOUT_CALLBACK: ansible.posix.json
  tasks:
  - name: create /tmp/foo.txt
    file:
      path: /tmp/foo.txt
      state: touch
...

 

stdout_callback directive

You can define the stdout_callback directive in your Ansible configuration file (ansible.cfg), where the higher option in this list will take precedence over the lower options.

  1. stdout_callback in ansible.cfg in the present working directory
  2. stdout_callback in .ansible.cfg in the user home directory (e.g. /home/john.doe/.ansible.cfg)
  3. stdout_callback in /etc/ansible/ansible.cfg

AVOID TROUBLE

The stdout_callback directive must be under the [defaults] header.

[defaults]
stdout_callback = ansible.posix.json

 

And now when you run your Ansible playbook, the console output should be JSON or YAML.

{
    "custom_stats": {},
    "global_custom_stats": {},
    "plays": [
        {
            "play": {
                "duration": {
                    "end": "2025-10-07T07:15:51.801833Z",
                    "start": "2025-10-07T07:15:51.319038Z"
                },
                "id": "00505687-1254-4d2e-bb06-000000000001",
                "name": "localhost",
                "path": "/home/john.doe/a:2"
            },
            "tasks": [
                {
                    "hosts": {
                        "localhost": {
                            "_ansible_no_log": false,
                            "action": "ansible.builtin.file",
                            "changed": true,
                            "dest": "/tmp/foo.txt",
                            "diff": {
                                "after": {
                                    "atime": 1759821351.78045,
                                    "mtime": 1759821351.78045,
                                    "path": "/tmp/foo.txt",
                                    "state": "touch"
                                },
                                "before": {
                                    "atime": 1759821331.4021,
                                    "mtime": 1759821331.4021,
                                    "path": "/tmp/foo.txt",
                                    "state": "file"
                                }
                            },
                            "gid": 100,
                            "group": "users",
                            "invocation": {
                                "module_args": {
                                    "_diff_peek": null,
                                    "_original_basename": null,
                                    "access_time": null,
                                    "access_time_format": "%Y%m%d%H%M.%S",
                                    "attributes": null,
                                    "follow": true,
                                    "force": false,
                                    "group": null,
                                    "mode": null,
                                    "modification_time": null,
                                    "modification_time_format": "%Y%m%d%H%M.%S",
                                    "owner": null,
                                    "path": "/tmp/foo.txt",
                                    "recurse": false,
                                    "selevel": null,
                                    "serole": null,
                                    "setype": null,
                                    "seuser": null,
                                    "src": null,
                                    "state": "touch",
                                    "unsafe_writes": false
                                }
                            },
                            "mode": "0644",
                            "owner": "c065234",
                            "secontext": "unconfined_u:object_r:user_tmp_t:s0",
                            "size": 0,
                            "state": "file",
                            "uid": 65234
                        }
                    },
                    "task": {
                        "duration": {
                            "end": "2025-10-07T07:15:51.801833Z",
                            "start": "2025-10-07T07:15:51.332662Z"
                        },
                        "id": "00505687-1254-4d2e-bb06-000000000003",
                        "name": "touch /tmp/foo.txt",
                        "path": "/home/john.doe/a:5"
                    }
                }
            ]
        }
    ],
    "stats": {
        "localhost": {
            "changed": 1,
            "failures": 0,
            "ignored": 0,
            "ok": 1,
            "rescued": 0,
            "skipped": 0,
            "unreachable": 0
        }
    }
}

 

On a Linux system, you could then pipe the JSON output into the jq command to return specific JSON keys.

~]$ ansible-playbook example.yml | jq .stats
{
  "localhost": {
    "changed": 1,
    "failures": 0,
    "ignored": 0,
    "ok": 1,
    "rescued": 0,
    "skipped": 0,
    "unreachable": 0
  }
}

 

Here is how you could loop through each task in your playbook.

ansible-playbook example.yml | jq --compact-output .plays[].tasks[] | while read item; do echo "TASK = $item"; done

 

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 0be8fb in the box below so that we can be sure you are a human.