# Log tail & templates

Source: https://www.pingtower.com/docs/service/logtail/

The actual lines behind an alert, filtered to the shape that matched. Kept only for sources that ask for it.

## Templates

A template is a message with the values you passed as `keys` substituted out. The substitution is literal: each key's value is searched for in the message and replaced with `{{ .name }}`, longest value first, every occurrence.

| Message | Keys | Template |
| --- | --- | --- |
| `user bob logged in` | `{"name":"bob"}` | `user {{ .name }} logged in` |
| `timeout after 30012ms for o_48113` | `{"order":"o_48113","latency_ms":30012}` | `timeout after {{ .latency_ms }}ms for {{ .order }}` |
| `disk full` | none | `disk full` |

The template's SHA-256 is its id, returned on every ingest response as `template_id` and carried by every alert as `template`. Two lines with the same template are the same thing to a rule and fold into the same alert.

<div class="docs-callout warn"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2 1.5 13.5h13L8 2Z"/><path d="M8 6.5v3M8 11.5v.5"/></svg><div><span class="t">Nothing is masked automatically</span>If a variable part of the message is not in <code>keys</code>, it stays in the template, and every distinct value opens its own alert. When you see a storm of near-identical alerts, the fix is almost always to move the changing part into a key.</div>
</div>


## Retaining lines

`retain_logs` is a per-source switch, off unless you set it. Only sources with it on have anything in the log tail. It is optional on create and must be sent explicitly on update: an omitted field on `PUT` is a `400`, not a silent `false`.

Retained rows are bounded by the plan's `max_logs`, the daemon's `-retain-days` (default 7) and `-max-logs-per-source` (default 10,000). Past a cap the oldest rows go first. Alerting is never affected.

## Reading the tail

<span class="pill get">GET</span> `/v1/projects/{id}/logtail`

| Parameter | Default | Meaning |
| --- | --- | --- |
| `limit` | 50 | 1 to 200 lines. |
| `template` | none | Only lines whose recovered template equals this string. Pass the alert's `template` to see just its lines. |

```sh
curl -s "$PT/v1/projects/checkout/logtail?limit=20&template=timeout%20after%20%7B%7B%20.latency_ms%20%7D%7Dms%20for%20%7B%7B%20.order%20%7D%7D" \
  -H "Authorization: Bearer ptk_…"
# → {"messages": ["…", "…"]}   newest last
```

In the app, an alert's detail screen reads this with the alert's own template already applied. A rule with `investigate: true` puts it first.
