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


4 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