> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firetone.com.au/llms.txt
> Use this file to discover all available pages before exploring further.

# Logs

> Three questions in one screen: why somebody cannot sign in, who changed a thing, and what the machine is actually doing.

**Logs** answers three different questions that get asked in the same
evening. Each is a tab.

| Tab            | Answers                        |
| -------------- | ------------------------------ |
| **Sign-ins**   | why this person cannot get in  |
| **Changes**    | who changed this               |
| **System log** | what the box is actually doing |

The first two are scoped to an organisation, so a tenant's own admin reaches
them. The third is not — a log line has no tenant against it — so it is the
operator's, and the tab is simply absent rather than failing after the click.

## Sign-ins

Every attempt at every door, accepted or refused, with the address it came
from and what was typed.

| Door              | Who uses it                                     |
| ----------------- | ----------------------------------------------- |
| **Panel**         | an email and a password                         |
| **Desk (PIN)**    | an agent, with their extension number and a PIN |
| **Handset (SIP)** | a phone, with its SIP password                  |
| **API key**       | a program                                       |

<Note>
  Most refusals are one door's credential typed into another. An agent's email
  at the panel, a SIP password at the desk. The screen says so under the
  table, because it is the answer often enough to be worth printing.
</Note>

A refusal carries the reason in words rather than as a code, and the useful
ones are the ones that are not about a wrong password:

* **No PIN set up for that extension** — the agent has never been given one.
* **The agent is on no team** — their sign-in has nothing to scope to. Add
  them to a team.
* **The agent is on several teams and none was chosen** — reset the PIN and
  pick one.
* **The handset gave the server's IP as its domain**, and that extension
  number exists in more than one organisation. Set the handset's SIP domain
  to its own organisation's.
* **The control plane could not check** — not a wrong credential. Something
  was down.
* **Too many attempts** — refused without even checking.

Filter by result and by door.

## Changes

Every create, update, replace and delete, with who did it, what the request
was in plain words, and whether it worked.

Reads are not recorded. A failed change is, with its status and the error,
which is often the more interesting row: somebody tried and was refused.

<Warning>
  **Secrets never land here.** A password, a PIN, an API key, a provider
  credential, a webhook's signing secret and an HTTP connection's headers are
  written as **«set»** — the field name is recorded, the value never is. An
  audit log that faithfully stored secrets would be a second place they live,
  and the encryption everywhere else exists precisely so there is only one.
</Warning>

The log is written in middleware rather than by each handler, so there is no
route that somebody forgot to add it to. It never fails a request either: a
database that is briefly slow must not turn a customer's successful change
into an error.

## System log

The daemon's journal and the switch's log, in one place, for the operator who
would otherwise need a shell on the box.

Filter by source, by level, and by what a line contains, then **Apply** —
it is not applied as you type, because each fetch reads the journal and the
tail of a file.

Newest first is the default, because the line explaining what just happened
is the one you came for. Choose oldest first to read a sequence in the order
it happened; a registration or a startup is unreadable backwards.

<Note>
  **A source that could not be read says so, in amber, with the reason.** It
  is never drawn as an empty list. "Could not ask" and "nothing happened" are
  opposite facts, and a calm empty panel for a box that is refusing every call
  would be the failure this screen exists to end.
</Note>

Reading the daemon's journal needs the daemon's user in the
`systemd-journal` group; reading the switch's log needs read permission on
the file. Both are named in the amber box when they are missing.

## Permissions

|                      | Needs        |
| -------------------- | ------------ |
| Sign-ins and Changes | `audit:read` |
| System log           | `logs:read`  |

`audit:read` is an organisation admin's as well as an operator's, and each
sees only their own tenant's rows. `logs:read` is the operator's alone.
