How to Capture and Debug Command Output (stdout) in Ansible Playbooks


16 views

When running Ansible playbooks, developers often need visibility into the actual command output (stdout) of executed tasks, not just Ansible's summarized status messages. The default verbosity flags (-v, -vv, etc.) show Ansible's internal operations but don't always surface the raw command output that's crucial for debugging.

Here are the most effective methods to capture command output:

- name: Basic stdout capture with register
  ansible.builtin.command: echo "hello world"
  register: cmd_output
  
- name: Display captured output
  debug:
    var: cmd_output.stdout

For complex scenarios, consider these approaches:

- name: Run shell command with full output
  shell: |
    echo "Line 1"
    echo "Line 2"
    echo "Error message" >&2
  args:
    executable: /bin/bash
  register: shell_out
  changed_when: false

- name: Show complete output
  debug:
    msg: "{{ shell_out.stdout_lines }}"

- name: Show stderr separately
  debug:
    msg: "{{ shell_out.stderr }}"

For long-running commands where you need immediate feedback:

- name: Stream output in real-time
  shell: |
    for i in {1..5}; do
      echo "Progress $i/5"
      sleep 1
    done
  environment:
    ANSIBLE_STDOUT_CALLBACK: debug
    ANSIBLE_LOAD_CALLBACK_PLUGINS: 1

Add these settings to ansible.cfg for persistent behavior:

[defaults]
stdout_callback = debug
bin_ansible_callbacks = True
display_args_to_stdout = True

When output doesn't appear as expected:

  • Verify no_log: false is set on tasks
  • Check for command output being redirected
  • Test with simple echo commands first
  • Ensure proper register variable usage

When running Ansible playbooks, many users struggle to see the actual stdout output from individual command/shell tasks. While the -v flag shows Ansible's internal output, it doesn't display the command results in a way that's immediately visible when debugging.

The most reliable method is to register the command output to a variable and display it:

- name: Execute command and show output
  ansible.builtin.command: echo "hello world"
  register: command_output
  
- name: Display command output
  debug:
    var: command_output.stdout

For more detailed output, combine these verbosity flags:

ansible-playbook playbook.yml -vvv

This shows both the command being executed and its output.

For long-running commands where you need immediate feedback:

- name: Stream command output
  shell: |
    for i in {1..5}; do
      echo "Iteration $i"
      sleep 1
    done
  register: streaming_output
  async: 45
  poll: 0
  
- name: Display streaming output
  debug:
    var: streaming_output.stdout_lines

When a command fails, Ansible automatically shows its output:

- name: Run command that might fail
  command: /path/to/script.sh
  ignore_errors: yes
  register: script_output
  
- name: Show error details if failed
  debug:
    var: script_output.stderr
  when: script_output.failed

Configure ansible.cfg for different output formats:

[defaults]
stdout_callback = debug

Other useful callbacks include yaml, json, or minimal.

Here's a complete playbook demonstrating various output techniques:

---
- hosts: localhost
  tasks:
    - name: Simple command output
      command: echo "Direct output example"
      register: simple_output
      
    - name: Show simple output
      debug:
        var: simple_output.stdout
        
    - name: Multi-line output handling
      shell: |
        echo "Line 1"
        echo "Line 2"
      register: multiline_output
      
    - name: Show multiline output
      debug:
        var: multiline_output.stdout_lines
        
    - name: Error case demonstration
      command: /bin/false
      ignore_errors: yes
      register: error_output
      
    - name: Show error details
      debug:
        var: error_output.stderr
      when: error_output.failed