As an Ansible user, you may frequently need to view the full output from commands and modules running on your remote hosts. Whether debugging issues, auditing changes, or gathering details about your systems, getting access to command output is crucial.
But by default, Ansible strives to be idempotent and quiet – it does not print output unnecessarily. Playbook runs will therefore not display the full output of commands, only changes made.
So how can you print stdout and stderr from Ansible tasks?
In this comprehensive guide, you‘ll learn 8 methods to save and print command output in Ansible:
- Using the
debugmodule to print variables - Writing output to a file on the control node
- Appending output to a log file with
lineinfile - Capturing output in a variable
- Handling stderr and failed commands
- Running long-running tasks asynchronously
- Printing output for changed tasks only
- Optimizing output printing for performance
These techniques will give you complete visibility into your Ansible automation activities and help troubleshoot issues faster.
Let‘s look at each method in detail, with examples you can apply in your playbooks.
Prerequisites for Printing Ansible Output
Before we dive in, let‘s quickly go over what you‘ll need:
- Ansible 2.9 or higher installed on your control node
- SSH access to your managed nodes from the control node
- A sample playbook to run commands – we‘ll use a simple one that runs
uptime:
---
- name: Sample playbook
hosts: webservers
tasks:
- name: Run uptime
command: uptime
This playbook runs uptime on the webservers host group. But as expected, it does not print the uptime output.
I‘ll be using Ubuntu 20.04 servers for the examples, but all methods work for any RHEL/Debian based Linux distros that Ansible can connect to.
Now let‘s look at the different ways to print and save this uptime output.
1. Using debug to Print Variables
The easiest way to print output from an Ansible task is by using the debug module. This module prints a debug message during playbook execution.
To capture command output into a variable, use the register keyword:
- name: Run uptime
command: uptime
register: uptime_out
This runs uptime and stores its output in the uptime_out variable.
Next, print the output with debug:
- name: Print uptime output
debug:
msg: "{{ uptime_out.stdout }}"
When you run the playbook, it will print the uptime output:
TASK [Print uptime output] ****
ok: [web1] =>
msg: ‘10:32:10 up 1 day, 23:12, 1 user, load average: 0.23, 0.45, 0.78‘
The debug module is great for printing short snippets of output. For larger outputs, it‘s better to save them to a file instead.
When to use debug
Use debug statements to print variables when:
- Output is a single line or less than 10 lines
- You need occasional debug messages in a playbook
- Printing output intermittently as playbook executes
Avoid using debug for long output as it will clutter up the terminal.
2. Writing Output to a File
For larger command output, redirect it to a file instead of printing directly. This keeps your console clean and allows further processing of the output.
Ansible provides a fetch module to copy files from managed nodes to the control node.
Here is an example playbook to save uptime output to a file:
---
- name: Run uptime
command: uptime
register: uptime_out
- name: Create local output file
copy:
content: "{{ uptime_out.stdout }}"
dest: /tmp/uptime.txt
- name: Fetch output file
fetch:
src: /tmp/uptime.txt
dest: /home/ansible/uptime.txt
flat: yes
This playbook does the following:
- Runs
uptimeand stores output inuptime_out - Creates
/tmp/uptime.txton the remote host with the output - Copies
/tmp/uptime.txtback to the control node as/home/ansible/uptime.txt
The flat parameter for fetch ensures the filename is preserved instead of organizing in host-specific directories.
You can now view the full uptime output in /home/ansible/uptime.txt on your control system.
When to use output files
Use output files when:
- Command output is large – more than 50 lines
- You want to save output for later processing and analysis
- To centralize output from multiple servers in one place
This technique is great for aggregating logs, configs, process lists, etc. from multiple systems onto your Ansible control node.
Avoiding duplicate data
One downside of writing command output to files is duplication if the command is run multiple times.
For continuously changing output like logs, use the lineinfile module instead to only append new changes.
We‘ll cover this method next.
3. Appending Output with lineinfile
For log and monitoring use cases, you often want to run the same command periodically and aggregate results over time.
Output should only be appended to the file, avoiding duplication.
Ansible‘s lineinfile module was designed for this purpose. It ensures a matching line is only written once to a file.
Here is an example that collects uptime daily and appends it to a log file:
---
- name: Run uptime
command: uptime
register: uptime_out
- name: Append uptime to log
lineinfile:
path: /var/log/uptime.log
line: "{{ uptime_out.stdout }}"
The first time this runs, it will create /var/log/uptime.log containing the uptime result.
Subsequent runs will check for an existing matching line, and only append if missing. This avoids duplicate entries.
Over time, the file will contain an aggregated log of historical uptime data.
When to use lineinfile
Use lineinfile when:
- You want to log command output over time without duplicates
- Collecting monitoring metrics in a central file
- Aggregating output from periodic playbook runs
This method is also useful for maintaining config files and log rotations.
4. Capturing Output in a Variable
You can also capture command output in a variable and use it later in your playbook.
For example:
- name: Get instance type
shell: curl http://169.254.169.254/latest/meta-data/instance-type
register: instance_type
- name: Print instance size
debug:
msg: "Instance type is {{ instance_type.stdout }}"
This queries the EC2 metadata API to get the instance type and saves it in a variable. The instance size can then be printed in a later task.
Storing output in a variable like this lets you reuse the result multiple times without re-running the command. Caching the output in memory avoids duplicate work.
You can also use facts gathered by Ansible to simplify this:
- name: Print Ansible version
debug:
msg: "Ansible version is {{ ansible_version.full }}"
This uses the existing ansible_version fact rather than running ansible --version to get the version string.
When to store output as variable
Use variables for command output when:
- You need to reuse the output in multiple tasks
- To avoid rerunning expensive commands repeatedly
- The output is small enough to store in memory
Variables are ideal for storing identities, versions, IPs, stats that can be referenced throughout a playbook.
5. Handling Errors and Warnings
Many commands will print warnings, errors or other status messages to stdout/stderr.
Ansible captures this output separately from regular stdout using the stderr, stderr_lines, and cmd variables.
For example, when using the apt module:
- name: Run apt-get update
apt:
update_cache: yes
register: apt_result
- name: Print failures
debug:
msg: "Errors: {{ apt_result.stderr }}"
This will print any errors or warnings from apt-get update for debugging.
You can also use failed_when to make a task fail if stderr is not empty:
- name: Run apt-get update
apt:
update_cache: yes
register: apt_result
failed_when: apt_result.stderr != ""
This will cause the playbook to fail if the apt-get command writes anything to stderr.
When to use stderr
Use stderr and failed_when to handle command errors:
- To debug issues with commands and playbooks
- Halt execution on any error by failing fast
- Gather error metrics and alerts
Capturing stderr allows you to build more resilient playbooks.
6. Using async for Long Running Commands
Certain commands can take a long time to run – from minutes to hours. By default Ansible will block and wait for them to complete before continuing.
To avoid this, you can run long-running commands asynchronously using the async parameter:
- name: Run database backup
command: /opt/backup_database.sh
async: 3600
poll: 10
register: db_backup
This will start the DB backup script and check on it every 10 seconds for up to 3600 seconds (1 hour).
The playbook will continue immediately without waiting for the backup to complete.
To print any output from the async process:
- name: Print async stdout
debug:
msg: "{{ db_backup.stdout_lines }}"
This will wait until the async process finishes and then print the stdout/stderr.
You can also chain a second playbook to check on the result later.
When to use async
Use async to run commands that take:
- More than 1 minute (good threshold to avoid blocking)
- Up to 1 hour (for longer background tasks use celery/Redis queues)
- Time periods unknown or variable (user input, network transfers)
Async allows your playbooks to continue while long-running tasks execute in the background.
7. Printing Output for Changed Tasks Only
A key benefit of Ansible is idempotence – after initial configuration, subsequent runs should only make changes if needed.
You can use this principle to print output only for tasks that actually changed something, using the changed_when condition.
For example:
- name: Install Apache
apt:
name: apache2
state: latest
register: install_result
- name: Print changed output
debug:
msg: "{{ install_result.stdout }}"
when: install_result.changed
The first run will print stdout from the apt module showing Apache being installed. But later runs will skip this debug message since no install occurred.
This avoids cluttering output with unchanged or duplicate task results.
When to use changed_when
Use changed_when and when conditionals to print output only for changed tasks:
- Reduce noise when playbooks are run frequently
- Focus on output for new changes rather than static info
- Alert on config changes or situations requiring investigation
This technique helps highlight the most important output for review.
8. Optimizing Output Printing for Performance
Printing command output using debug has a performance cost, especially for large output. Ansible will capture the output even if you don‘t print it.
You can optimize this by only registering variables and printing output conditionally when needed.
For example:
- name: Run uptime
command: uptime
register: uptime_out
when: debug_uptime
- name: Print uptime
debug:
msg: "{{ uptime_out.stdout }}"
when: debug_uptime
Here a debug_uptime variable controls whether output is printed. This can be toggled on/off as needed.
You can also set this conditionally:
- set_fact:
debug_uptime: true
when: dev_servers
Now uptime will only print for hosts in the dev_servers group, avoiding the performance hit elsewhere.
When to optimize output printing
Use conditional printing when:
- Playbooks will run frequently (more than daily)
- Performance is a concern
- Verbose output is only needed temporarily (debugging)
There is a speed vs. visibility tradeoff, so enable conditional output on a case-by-case basis.
Summary of Output Printing Techniques
Here is a quick summary of the 8 methods covered in this guide:
| Method | When to Use |
|---|---|
| debug module | Short output, intermittent debugging |
| Write to file | Large output, save history |
| lineinfile | Append logs/history, avoid dupes |
| Register variables | Reuse output, avoid rerunning commands |
| Capture stderr | Handle errors and warnings |
| Async tasks | Long running commands >1 min |
| changed_when | Print output only for changes |
| Optimize conditionally | Increase speed, reduce noise |
As you can see, Ansible provides flexible options to control command output.
The best approach depends on your specific use case – debugging errors, monitoring over time, aggregating data, etc. Combining several methods is also common.
I recommend erring on the side of more verbosity initially during playbook development. Then optimizing and cleaning up output for production use.
Conclusion
Being able to print and save command output is crucial for administering systems with Ansible. This guide covered 8 techniques for capturing and displaying output from your playbooks.
Here are some key takeaways:
- Use
debugto print short snippets and variables inline - For larger output, redirect and save to a file on your control node
- Append unique output lines to a file with
lineinfile - Store frequently used results in variables instead of rerunning commands
- Handle errors and warnings using
stderrandfailed_when - Run long-running commands asynchronously to prevent blocking playbook execution
- Print output selectively for changed tasks using
changed_when - Conditionally control output only when needed for performance
Following Ansible best practices of idempotence and minimal output is recommended in production. Only print extra details when debugging and in development.
Overall having access to complete command output gives you visibility and power over your infrastructure. Apply these techniques and you‘ll be able to monitor systems, troubleshoot issues faster, and automate workloads seamlessly with Ansible.


