# Log profile — a format for an AI to write

A **log profile** is a short JSON document describing what one team's logs look like. You paste it
into the "Log profile" box in [jarroba.com/tools/en/logs](/en/logs) and the session is configured:
format, server time zone, the prefix of your own code, which lines are noise, and how much budget
to give the AI-oriented reduction.

**Why it exists.** Those five things are not in the log — you have to know them — and they are what
separates "opening a file" from "the tool configured for MY system". Typing them by hand every time
is tedious; describing them once to a model, with a sample of the log in front of it, takes a minute.

> **If you are an AI:** you are given a sample of the log (30–100 lines is enough) and you return
> **only** the JSON, with no prose around it. Whatever you do not know, **leave it out**: everything
> is optional except `logprofile`. Making up the server time zone is worse than omitting it — that
> fact is not in the log, and if you invent it the whole timeline is wrong and nobody notices.

## Full example

```json
{
  "logprofile": 1,
  "name": "Orders API (Spring Boot)",
  "format": "plain",
  "sourceZone": "Europe/Madrid",
  "displayZone": "Europe/Madrid",
  "appPrefixes": ["com.acme."],
  "eventStart": "^\\[\\d{4}-",
  "levels": ["warn", "error", "fatal"],
  "rules": [
    { "label": "timeout", "pattern": "SQLTransientConnectionException", "action": "highlight", "color": "#e53935" },
    { "label": "noise", "pattern": "^.*GET /health.*$", "regex": true, "action": "hide" },
    { "label": "payments", "pattern": "PaymentService", "action": "pin", "color": "#8e24aa" }
  ],
  "ai": { "maxTokens": 8000, "redact": true, "digest": false, "keepTraces": true, "context": 5 }
}
```

## Fields

| Field | Type | What it is |
|---|---|---|
| `logprofile` | `1` | **Required.** The marker that tells a profile apart from any other JSON. |
| `name` | text | A name so you can recognise it. |
| `format` | see below | Forces the format. **Leave it out for ordinary plain text**: the tool detects it on its own and gets it right. |
| `sourceZone` | IANA zone | Which time zone the clock that **wrote** the log was in. It only affects timestamps that carry **no** zone of their own; one with `Z` or `+02:00` is already an exact instant and is left alone. |
| `displayZone` | IANA zone | Which time zone to **show** times in. The raw line is never rewritten. |
| `appPrefixes` | list of text | Prefixes of your own code (`"com.acme."`, `"src/"`). This is what lets the tool point at the guilty frame in a stack trace instead of a framework one. |
| `eventStart` | text (regex) | Which line STARTS an event. Only needed if the log does not timestamp every line or brings its own header: by default it is inferred from the timestamp. If given, it wins over that inference. Examples: `"^=== "`, `"^\\[\\d{4}-"`. A broken regex is an error in the profile, reported with its field, not an exception halfway through the analysis. |

> **Write `eventStart` as an exclusion, not as a list of known prefixes.** A rule like
> `^(gcc |npm |make\[\d+\]:)` breaks the moment a command outside the list shows up — a `strip`, a
> project's own script: that line glues itself to the previous event and **disappears as a command**,
> and the list can never be finished. The rule that holds is the opposite one: *an event starts with
> anything that is not indented and is not a `note:`* — e.g. `^(?![ \t])(?!note:)`. Found the hard
> way by `/proyecto` on build logs.
| `levels` | list | Levels visible on open. Absent or empty = all of them. |
| `rules` | list | Highlighting rules (see below). |
| `ai` | object | Settings for the "For AI" tab. |

`format`: `json` · `logfmt` · `syslog5424` · `syslog3164` · `clf` · `combined` · `plain`
`levels`: `trace` · `debug` · `info` · `warn` · `error` · `fatal`

### `rules[]`

| Field | Type | What it is |
|---|---|---|
| `pattern` | text | **Required.** What to look for in the line. |
| `regex` | boolean | `true` to treat `pattern` as a regular expression. If `false` (or missing), it is matched literally. |
| `caseSensitive` | boolean | Match case. Off by default. |
| `action` | `highlight` · `hide` · `pin` | What to do. Defaults to `highlight`. |
| `color` | `#rrggbb` | Highlight colour. Not used with `hide`. |
| `label` | text | A short label. |

### `ai`

| Field | Type | What it is |
|---|---|---|
| `maxTokens` | 200 – 1000000 | Budget for the reduction. Counted with the model's real tokenizer. |
| `context` | 0 – 50 | How many events to keep **before** each error. Without them there is no way to tell what caused it. |
| `redact` | boolean | Mask keys, tokens, emails, cards and IBANs before copying. |
| `digest` | boolean | Return a **report** instead of a shorter log. |
| `keepTraces` | boolean | Keep whole stack traces, or fold them down to their summary. |

## Rules of the format

1. **Everything is optional except `logprofile`.** A bare `{"logprofile": 1}` is valid and changes
   nothing.
2. **What you do not know, leave out.** A missing field leaves that setting as it was; an invented
   field misconfigures the tool without anyone noticing.
3. **Errors are never applied halfway.** If anything fails validation, NOTHING is applied and every
   problem is listed at once, with the exact field (`rules[2].pattern`) and what was expected.
4. An unknown field **warns but does not invalidate**: the rest of the profile still applies.
5. Regular expressions are checked at validation time, not when a log is opened: a broken regex
   shows up here and can be fixed before the profile is handed over.

## How to ask a model for one

> Here are 60 lines of my log. Write me a Jarroba Tools **log profile** (`logprofile: 1` format)
> following `logprofile.md`. Return only the JSON. Do not set `sourceZone` if you cannot tell from
> the log — I can tell you the server was on `Europe/Madrid`.

You can also ask the tool itself to **propose one** ("Propose one from this log"): it infers the
format, the prefix of your own code from the stack traces, and a starting set of rules from the most
frequent errors and whatever floods the file. That leaves only what genuinely has to come from
outside: the server's time zone.

## Over MCP

The Jarroba Tools MCP server exposes two tools for this:

- `log_profile_check` — validates a profile and returns the errors explained. It lets a model
  correct itself before handing anything over.
- `log_profile_suggest` — proposes a profile from a log (accepts a **file path**).
