Introduction
Callback plugins customize what Ansible does during execution — change output format, profile task timing, send notifications on failure, or integrate with monitoring. They hook into events like task start, task completion, play end, and runner failure.
Built-in Callbacks
Change Output Format
# ansible.cfg
[defaults]
stdout_callback = yaml
| Callback | Description |
|---|---|
default | Standard output |
yaml | YAML-formatted (most readable) |
json | JSON output |
dense | Minimal one-line per task |
debug | Verbose debug output |
minimal | Bare minimum |
null | No output |
tree | Save output per host to files |
unixy | Unix-style condensed |
Enable Additional Callbacks
[defaults]
stdout_callback = yaml
callbacks_enabled = timer, profile_tasks, profile_roles
Profile Tasks (Performance)
# ansible.cfg
[defaults]
callbacks_enabled = timer, profile_tasks
Output shows timing for every task:
PLAY RECAP ****
Monday 12 April 2026 14:30:00 +0000 (0:00:05.123) 0:01:23.456 ***
===============================================================================
Install packages ------------------------------------------ 45.23s
Deploy configuration -------------------------------------- 12.45s
Start services -------------------------------------------- 5.12s
Gather facts ---------------------------------------------- 3.89s
profile_roles
callbacks_enabled = profile_roles
Shows total time per role:
Role Time
nginx 23.45s
myapp 45.12s
monitoring 12.33s
Notification Callbacks
Slack Notification
# ansible.cfg
[defaults]
callbacks_enabled = community.general.slack
[callback_slack]
webhook_url = https://hooks.slack.com/services/T00/B00/xxx
channel = #ansible
username = ansible-bot
Email on Failure
[defaults]
callbacks_enabled = community.general.mail
[callback_mail]
to = ops@example.com
sender = ansible@example.com
smtphost = smtp.example.com
Log to Syslog
[defaults]
callbacks_enabled = community.general.syslog_json
Log to File (JSON)
[defaults]
callbacks_enabled = community.general.log_plays
log_path = /var/log/ansible/plays.log
Custom Callback Plugin
# callback_plugins/custom_notify.py
from ansible.plugins.callback import CallbackBase
class CallbackModule(CallbackBase):
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'notification'
CALLBACK_NAME = 'custom_notify'
CALLBACK_NEEDS_ENABLED = True
def v2_runner_on_failed(self, result, ignore_errors=False):
if not ignore_errors:
host = result._host.get_name()
task = result._task.get_name()
msg = f"FAILED: {task} on {host}"
# Send to your notification system
self._display.warning(msg)
def v2_playbook_on_stats(self, stats):
hosts = sorted(stats.processed.keys())
failures = False
for h in hosts:
summary = stats.summarize(h)
if summary['failures'] > 0 or summary['unreachable'] > 0:
failures = True
if failures:
self._display.warning("PLAYBOOK HAD FAILURES!")
# Send alert
def v2_runner_on_ok(self, result):
pass # Task succeeded
def v2_runner_on_skipped(self, result):
pass # Task skipped
# ansible.cfg
[defaults]
callback_plugins = ./callback_plugins
callbacks_enabled = custom_notify
Event Hooks
| Hook | Fires When |
|---|---|
v2_playbook_on_start | Playbook begins |
v2_playbook_on_play_start | Play begins |
v2_playbook_on_task_start | Task begins |
v2_runner_on_ok | Task succeeds |
v2_runner_on_failed | Task fails |
v2_runner_on_skipped | Task skipped |
v2_runner_on_unreachable | Host unreachable |
v2_playbook_on_stats | Playbook ends (summary) |
v2_on_any | Any event |
Practical Patterns
CI/CD with JSON Output
# Machine-readable output for CI
ANSIBLE_STDOUT_CALLBACK=json ansible-playbook site.yml > output.json
# Parse results
import json
with open('output.json') as f:
results = json.load(f)
for play in results['plays']:
for task in play['tasks']:
for host, result in task['hosts'].items():
if result.get('failed'):
print(f"FAILED: {task['task']['name']} on {host}")
Performance Debugging
# Find slow tasks
[defaults]
callbacks_enabled = timer, profile_tasks, profile_roles
# Sort tasks by duration
ansible-playbook site.yml 2>&1 | grep -E "^[A-Za-z].*---" | sort -t'-' -k2 -rn
ARA (Ansible Run Analysis)
pip install ara
# ansible.cfg
[defaults]
callbacks_enabled = ara_default
ARA provides a web UI to browse and analyze playbook runs.
Troubleshooting
Callback Not Loading
# List available callbacks
ansible-doc -t callback -l
# Check specific callback
ansible-doc -t callback yaml
# Verify callbacks_enabled in config
ansible-config dump | grep callback
Permission Denied on Custom Plugin
Ensure the file is readable and the directory is in callback_plugins path:
[defaults]
callback_plugins = ./callback_plugins
Related Articles
Conclusion
Callback plugins customize Ansible's behavior during execution. Use yaml for readable output, profile_tasks to find slow tasks, and notification callbacks for alerting. For CI/CD, use json output for machine parsing. Custom callbacks let you integrate with any monitoring or notification system. Always enable timer and profile_tasks in production to track performance over time.