Skip to content
changelog

What shipped, and when.

Backfilled from the commit history. Parsemend's history starts on the day the ingest pipeline first accepted an event from an unmodified Sentry SDK, which is why every entry below carries the same date.

fixed

Ingest hardening

A gzip bomb could OOM the worker; a dedup key silently dropped events; hex parameterization collapsed distinct errors.

Four fixes worth naming, because each was a real defect rather than a tidy-up:

  • Decompression is now bounded on both ends. The compressed body is rejected before a byte is inflated, and the inflate runs in 4 KiB chunks that abort the moment cumulative output passes the cap. Inflating first and checking the length afterwards meant a few dozen KiB of zeros could expand into gigabytes and take the worker down with an uncatchable OOM instead of a clean 413.
  • The digest dedup key no longer silently drops events. Two distinct events arriving in the same envelope could collide on the key and one would vanish.
  • Hex parameterization no longer collapses distinct error messages. Messages differing only in a hex substring were being folded into one issue.
  • Future client timestamps are clamped. A device with a wrong clock could write an event into a partition that did not exist yet.
added

Issue triage UI

Issue list with status, level and project filters; issue detail with stack trace, breadcrumbs, tags and contexts.

The issue list filters by status, level and project, and searches title and culprit. The detail view renders the stack trace, the breadcrumbs leading up to the throw, the indexed tags and the event contexts.

Organizations are a tenancy boundary, and issues cannot be reassigned across it.

added

Rate limiting and reason-coded outcomes

Per-key fixed-window limiting that answers with 429, Retry-After and X-Sentry-Rate-Limits.

Over quota, Parsemend responds the way a Sentry SDK already expects: 429, a Retry-After header, and X-Sentry-Rate-Limits naming the category and scope. The SDK backs off without any change on your side.

Every dropped event is counted against a reason — invalid, rate_limited, filtered — so "where did my events go" has an answer.

added

Partitioned events table and retention

Events live in a Postgres range partition per day. Expiring a day is a DDL statement, not a mass delete.

events is range-partitioned by received_at. A scheduled command creates partitions ahead of time and drops the ones past their retention window.

The alternative — DELETE FROM events WHERE received_at < ? — holds locks and leaves the table to vacuum for an hour. Dropping a partition takes milliseconds. Default retention is 90 days.

added

Issue counters, tags and regression detection

Denormalized counters, an indexed tag table, and resolved issues that flip back to regressed on the write path.

Each issue carries times_seen, an approximate user count backed by a Redis HyperLogLog, and a per-day event bucket. Tags, environments and releases are indexed into a key/value table rather than scanned out of JSON at query time.

A resolved issue that sees a new event flips to regressed as the event is written. No cron job, no nightly sweep.

added

Grouping cascade

Custom fingerprint, then in-app frame signatures, then exception type and value, then a parameterized message.

Grouping tries four strategies in order, and stops at the first that applies:

  1. A custom fingerprint, including {{ default }} expansion.
  2. Signatures of the in-app stack frames, with recursion collapsed.
  3. The exception type and value, skipping the type when the mechanism is synthetic.
  4. The message, with variable parts parameterized out.

Many hashes can fold into one issue through the group_hashes table, so merging two issues does not lose the events that arrived under the old hash.

added

Envelope parser with unknown-type tolerance

A byte-offset scanner handling both length-prefixed and newline-terminated items.

Sentry's envelope format delimits items two different ways: a length prefix, or a newline. Real SDKs use both, sometimes in the same payload, and a length-prefixed item may contain newlines of its own.

The parser is a byte-offset scanner rather than a line splitter, which is the only way to get this right. Golden-file fixtures captured from the real PHP and Node SDKs keep it that way.

added

Sentry-compatible ingest

The envelope endpoint, the legacy store endpoint, and all three DSN authentication forms.

Parsemend accepts events at POST /api/{project}/envelope and at the legacy POST /api/{project}/store. The DSN key is read from the X-Sentry-Auth header, from a sentry_key query parameter, or from the dsn field in the envelope header — whichever your SDK happens to use.

Envelope item types Parsemend does not store are consumed and counted rather than rejected. An SDK that sends a transaction alongside an error will not start erroring because we do not keep the transaction.

Subscribe via RSS.