Okapi

Issues & logs

Grouping (fingerprinting)

Every incoming event is grouped into an issue by a computed fingerprint, in this order of precedence:

  1. Explicit fingerprint — if the event carries a fingerprint, Okapi uses it for manual grouping control. A {{ default }} element expands the default grouping within that fingerprint.
  2. Exception type + stacktrace hash — otherwise, the exception type plus the in-app stacktrace frames (frames from your own code). If there are no in-app frames, all frames count. A frameless exception groups by type and normalized value. Exception chains select the relevant cause.
  3. Stacktrace or message — with no usable exception, top-level stacktrace frames take precedence; otherwise, the normalized message determines grouping.

With a stack, the frame functions and files decide the group. Line numbers and changes in the message do not, and repeated identical frames from recursion count once.

Normalized messages. Without a stack, Okapi groups by a normalized copy of the message. Before grouping, it replaces email addresses, UUIDs, long hexadecimal strings and git SHAs, IP addresses, dates and times, durations, decimals, and numbers with four or more digits. In a URL, only the scheme and host count. Numbers with one to three digits stay as they are, so HTTP 404 and HTTP 500 stay separate issues, and so do Order 123 and Order 456. The message you see, and the raw payload, do not change.

Causes, groups and wrappers. In an exception chain, Okapi prefers the root-most cause with a stack from your own code. In an exception group (is_exception_group), it follows the leaf causes. Synthetic exceptions that an SDK makes from a non-error value, and a few known framework wrappers (React's recovered-render error, RxJava's undeliverable and not-implemented wrappers, and Kotlin coroutine and Jetpack Compose diagnostic exceptions), are skipped when a real cause exists.

Explicit fingerprints are used literally: Okapi never normalizes their elements. A fingerprint that is only {{ default }} is the same as no fingerprint.

Grouping versions. The grouping key carries a version. When an Okapi release changes the rules, existing issues keep their old keys, and the next event of each recurring error opens a new issue. There is no link between the old issue and the new one. See Upgrading to 0.9.

Events that fingerprint the same way collapse into one issue with a short id like OKAPI-1, OKAPI-2, and so on — bumping times_seen/last_seen on every repeat rather than creating a new row.

Issue lifecycle

An issue can be:

  • Resolved — marked fixed.
  • Unresolved — the default state, or a manual reversal of resolved/ignored.
  • Ignored — silenced without being marked fixed.
  • Snoozed — silenced for a set period; automatically reverts to unresolved when the snooze expires.
  • Deleted — removed entirely.

Every action works on a single issue or in bulk — bulk actions accept either an explicit list of issue ids or a "select all matching the current filter" mode. You can also copy any event's raw payload as JSON from the issue view.

Regressions. If a resolved issue's fingerprint sees a new event, it reopens and is flagged as a regression — distinct from an issue that was simply never resolved.

Structured logs

Okapi collects structured logs over the same DSN as errors — enable your SDK's logging feature and logs flow in automatically (see SDK setup). Logs carry structured attributes stored as JSONB and indexed with a GIN index, so attribute search stays fast even at volume.

View and search logs under a project's Logs tab: filter by level, time range, message text, and attribute key:value. Logs are pruned per OKAPI_LOG_RETENTION_DAYS (default 30, per-organization entitlement overrides the instance default). Okapi's MCP server (/mcp) also exposes a search_logs tool for AI agents — see MCP & agents.

Releases and regressions

Okapi tracks the first-seen release for each issue when your SDK reports a release on its events. Combined with the regression flag above, this gives you a straightforward story: "first seen in release X, resolved, came back in release Y."

To read several projects as one list, see Views.

Next: Performance monitoring for traces and slow queries, then Views and Alerts & notifications to get notified when any of this happens.