Skip to content
slopscale
Esc
↑↓navigate↵open⌘Jpreview
On this page

Audit log

Read, filter and export the append-only audit log of API changes and sign-ins from the CLI, the API or the console, and set how long events are kept.

Slopscale records who changed what. Every writing request to the API, from the CLI, the admin console or any other client, becomes one audit event once it has run, and so do the sign-in events the server performs itself. The log is append-only; nothing in the API edits or deletes it.

What an event holds

Field Meaning
createdAt When the request finished.
actorKind How the caller authenticated: local (the unix socket, so the CLI on the server), api_key, oauth, session (a console sign-in), node (a machine reporting through the control protocol: node.client.disconnect when a machine under an always-on device policy records why its user disconnected) or system (the server on its own).
actorUserId, actorName The user behind the credential, by ID and by the name it had then. A key without a user records its prefix as the name.
action What happened, dotted and object first: user.role.set, node.delete, preauthkey.create, policy.set, console.login. A system user.role.set with source: oidc.admin_users is a promotion by configuration.
targetKind, targetId, targetName The object acted on, copied by value so the entry stays readable after the object is gone.
outcome The HTTP status the request ended with. A refused request (403, 404, 409) is recorded too; an unauthenticated one (401) is not, since it has no actor.
detail Action-specific fields: the new role, the routes approved, the tags set, a key’s expiry. Never a secret: keys appear as their prefix, the policy as its size.
remoteAddr The caller’s IP address.

Actions are listed in the OpenAPI document: each writing operation carries x-audit-action.

Reading the log

From the CLI:

$ slopscale audit list
$ slopscale audit list --action node. --limit 20
$ slopscale audit list --user 3 --since 2026-09-01T00:00:00Z
$ slopscale audit list --since 24h --target-kind node

--since takes an RFC 3339 time or a duration back from now. The next page is --before <id of the last event shown>.

Or from the API, newest first:

$ curl -H "Authorization: Bearer $KEY" \
    "https://slopscale.example.com/api/v1/audit?action=user.role.set&limit=50"

action keeps one action, or every action under a prefix when it ends with a dot (node. keeps every node action). actorUserId, targetKind and targetId keep one actor or one object; since and until bound the time. Pages follow the nextBefore cursor: pass it as before to get the next page.

Reading the log needs the logs:configuration:read scope, which every role except member holds. The console shows it under Audit log. To ship it to a SIEM as it is written, see Log streaming.

Exporting

GET /api/v1/audit/export returns the audit log as a file instead of a JSON page. It takes the same filters as the list, actorUserId, action, targetKind, targetId, since, until and before, plus format, which is csv (the default) or json. Events come oldest first, so a spreadsheet reads top to bottom in the order things happened. The console’s Audit log page has an Export button for the window and filters on screen, and the CLI writes the same file:

slopscale audit export --since 2026-09-01T00:00:00Z --until 2026-10-01T00:00:00Z -o audit-september.csv

The CLI takes the same filters as slopscale audit list, --user, --action, --target-kind, --target-id, --since and --before, and adds --until and --format. --since and --until accept an RFC 3339 time or a duration back from now, such as 24h. Without --output the file is written to stdout, so it can be piped.

curl -H "Authorization: Bearer $SLOPSCALE_API_KEY" \
  "https://slopscale.example.com/api/v1/audit/export?since=2026-09-01T00:00:00Z&until=2026-10-01T00:00:00Z" \
  -o audit-september.csv

The response is an attachment, text/csv; charset=utf-8 or application/json, named after the window it covers (audit-20260901T000000Z-20261001T000000Z.csv). Without since the name starts at start; without until it ends at the time of the request.

The CSV has a header row and one row per event, with the columns id, time, action, actorKind, actorUserId, actorName, targetKind, targetId, targetName, outcome, remoteAddr and detail. time is RFC 3339 in UTC, outcome is the HTTP status the request ended with, and detail is the action’s own fields as JSON in a single cell. The JSON format is one array of the same events in the shape GET /api/v1/audit returns them.

The server reads the log in batches while it writes the response, so the export never sits in memory, and it stops at 100000 events. When a filter matches more than that, the file holds the oldest 100000 and the newest are left out; export one window at a time with since and until to get all of them.

Exporting needs the logs:configuration:read scope, the same as reading the list, and is a read: it records no audit event of its own.

Retention

Events are kept forever by default. To bound the table, set a retention in the configuration; an hourly collector deletes older events:

audit:
  retention: 2160h # 90 days

Last updated on September 27, 2026

Was this page helpful?