AnsibleXLIII · Observability and Auditing of AutomationObservability and auditing
Reporting outward without making it mandatory
What you'll learn
- Evaluate an outward integration by the question it answers that the artefact does not
- State the cost a notification callback imposes on every run
- Keep a reporting integration off the critical path of a production change
- Assess what leaves your controller when run data is sent to a third party
- Recognise the coverage gap a platform job history does not close on its own
Prerequisites
Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11
Everything so far in this part stays on the controller: a log file, a structured artefact, some queries over them. That is deliberate. It is the baseline this course recommends, it costs nothing to operate, and it answers most of the questions an operator actually has.
This lesson is about the things you can add on top, and it is written as an evaluation rather than a recommendation, because each of them buys something real and charges for it in a way that is easy to miss until the charge arrives.
One question decides most of them:
What does this integration answer that the run artefact does not?
If the answer is “nothing, but it is more visible”, that is a legitimate reason — visibility is worth something. It is just a different reason from “we cannot currently answer X”, and confusing the two is how estates end up with three reporting systems and no evidence chain.
The three categories
Notification callbacks push events outward as they happen. The
community.general collection carries the familiar ones —
community.general.slack, community.general.mail and
community.general.log_plays among them — and all of them are collection
content, not ansible-core, so they are a pinned dependency like any other.
They answer: did the run happen, and how did it end? — to people who are not watching a terminal.
External run recorders capture the whole run into a queryable store. ARA is the established one: it records plays, tasks, hosts and results into a database and gives you a web interface and an API over them.
It answers: what happened across many runs, without writing queries against files?
Platform job history — AWX or Automation Platform — makes the run a first-class object with an owner, a status, a log and an inventory snapshot. Part XXXIX’s platform object model lesson owns this subject; here it appears only as one of three ways to get run history.
It answers: who ran what, with which credentials, against which inventory — with identity established before the run rather than inferred afterwards.
The costs, stated honestly
Callbacks run in the controller process
This is the cost people meet first and attribute to something else.
A notification callback is code executing inside ansible-playbook, on the
controller, synchronously with the run. A webhook with a five-second
connect timeout, fired per task, on a play with 200 tasks, adds time to
every run — and the failure mode when the endpoint is slow rather than down
is worse, because the run does not fail, it just takes twice as long and
nobody knows why.
The rule that follows: notify at run level, not at task level. A single message at the end of the run, containing the recap, costs one request. A message per task costs 200, and nobody reads them.
A reporting failure must not be a change failure
The design principle for anything in this lesson:
A production change must not depend on a chat service, a ticketing system or a recording database being available.
The reasoning is straightforward once stated. The runs you most need to complete are the ones during an incident, and an incident is exactly when your chat provider, your ticketing system or your internal database is most likely to be degraded — sometimes by the same underlying cause.
Practically:
- Test the integration’s failure path, deliberately, before relying on it. Point it at an unreachable endpoint and run a play. If the run fails, or hangs for minutes, you have created a dependency and you found out cheaply.
- Keep timeouts short on anything a callback contacts.
- Prefer aggregating at the end over streaming during, so a failed notification costs you a message rather than a run.
Sending run data outward is sending module results outward
Everything from lesson 3 applies, with the boundary moved.
A notification callback that includes task results is transmitting whatever
those tasks returned — including anything no_log did not cover — to a
third-party service, where it is retained under somebody else’s policy,
searchable by everyone in the channel, and subject to their breach history
rather than yours.
An external recorder is a system you now operate
ARA and its equivalents give you a real query interface, and in exchange you are running a database and a web service.
That has consequences that are ordinary and easy to underestimate:
- It needs backup, patching, capacity and a restore procedure — and it is now part of your audit trail, so losing it loses evidence.
- It has an access-control question of its own: it holds task results from every run, which makes it approximately as sensitive as the controller.
- It is one more thing that can be down during the incident when you want to query it, which argues for keeping the file artefacts as well rather than instead.
None of that is an argument against it. It is an argument for deciding deliberately, because a recorder adopted casually becomes an unowned service holding your audit evidence.
Platform job history does not cover the runs that bypass it
The strongest of the three, with one specific gap.
A platform records the runs made through the platform. Runs made by somebody with a checkout and a terminal are invisible to it — and adopting a platform tends to create a confident belief that all runs are recorded, which is more dangerous than knowing they are not.
Closing that gap is an access decision rather than a tooling one: the automation account’s credentials live only on the platform, so a laptop cannot reach the fleet at all. Until that is true, the platform’s job history is a record of the disciplined runs and not of the interesting ones.
Choosing
ansible-config dump --only-changedIf log_path is set, a structured callback is enabled and artefacts carry
the metadata from lesson 4, you already have an evidence chain. Add outward
integrations against a named question:
| Question | Smallest thing that answers it |
|---|---|
| Did the nightly run happen and how did it end? | A run-level notification, or an alert on artefact absence |
| Which host did this run touch? | The artefact — no integration needed |
| What changed across the fleet last month? | Queries over retained artefacts |
| Who ran this, established rather than inferred? | Platform job history, or CI with authenticated requesters |
| Can a non-operator see run history without shell access? | An external recorder, or a platform |
| Is this run slower than usual? | Timing callbacks plus retained artefacts |
Two rows in that table are answered by things you already have. That is the point of the table.
Knowledge check
Knowledge check · 4 questions
Q1. A team enables a chat notification callback that posts on every task. Runs get slower and nobody can say why. What is the mechanism?
Q2. What gap remains after adopting a platform whose job history records every run made through it?
Q3. Which of these are real costs of an external run recorder such as ARA? Select all that apply.
Q4. Enabling a notification callback in ansible.cfg applies it to every playbook in the repository, including dry runs, which is usually not what a team wants.
Passing score: 75%. Answers are checked in this browser.