---
url: /apranik/configuration/log.md
---
# Log

Where log records go, and how much is written.

## Structure

```json
{
  "log": {
    "level": "info",
    "outputs": [
      { "type": "stderr", "format": "human", "color": true },
      { "type": "file", "path": "apranik.log" }
    ]
  }
}
```

> \[!NOTE]
> With no outputs, Apranik logs nothing, on purpose: a log naming what a user
> reached is evidence on a seized device.

## Fields

### `level`

string
Default: info

The least severe level written, from most to least verbose: `debug`, `info`,
`notice`, `warning`, `error`, `critical`, `alert`, `emergency` (RFC 5424).

### `outputs`

list of outputs
Default: \[], silent

Where records go. Every record goes to every output. Each output's `type` is one
of the [output types](#output-types).

## Output types

:::tabs
\== stderr

```json
{
  "type": "stderr",
  "format": "human",
  "color": true
}
```

### `format` {#format}

string
Default: logfmt

| Value | Writes |
| --- | --- |
| `logfmt` | `time=… level=INFO msg="Inbound active" tag=socks-in` |
| `json` | `{"time":"…","level":"INFO","msg":"Inbound active","tag":"socks-in"}` |
| `human` | `2026-09-27T05:24:55.324+03:30 INFO      Inbound active tag=socks-in` |

Use `human` when a person reads the terminal.

### `color`

boolean
Default: false
human only

Color the level name and dim the time. `NO_COLOR` in the environment turns it
off.

\== file

```json
{
  "type": "file",
  "path": "/var/log/apranik.log",
  "format": "json"
}
```

### `path`

string
Required

The file to append to. It is created with mode `0600` if missing.

### `format` {#file-format}

string
Default: json

`json`, `logfmt` or `human`, as for [stderr](#format). A file is never
colored.

> \[!WARNING]
> A log file outlives the process and is evidence on a seized device.

\== memory

```json
{
  "type": "memory",
  "capacity": 256
}
```

### `capacity`

integer
Default: 256

How many recent records to keep in memory, for a Go program embedding
Apranik to read.

\== syslog

```json
{
  "type": "syslog",
  "network": "udp",
  "address": "10.0.0.2:514",
  "tag": "apranik"
}
```

### `network`, `address`

string
Default: the local daemon

Where the syslog daemon listens. Both empty means the local one.

### `tag`

string
Default: the program name

The tag on each message.

Not available on Windows or Plan 9; there it is refused at startup.

:::

## Live view for an API

An [API](api/index.md) can subscribe to the log at its own level, without any
output configured. With no subscriber this costs nothing. A subscriber that falls
behind loses records and is told how many.
