Skip to content

mkException puts the rendered exception text in class, breaking Rollbar grouping #98

Description

@resparza95

Problem

mkException fills the class field with the full rendered exception text:

-- rollbar-client/src/Rollbar/Client/Item.hs
mkException :: E.Exception e => e -> Exception
mkException e = Exception
  { exceptionClass = T.pack $ E.displayException e
  , exceptionMessage = Nothing
  , exceptionDescription = Nothing
  }

This contradicts the Exception type's own field docs (exceptionClass — "The exception class name", exceptionMessage — "The exception message, as a string") and Rollbar's API, which uses class as the primary grouping key for trace payloads. Since every distinct message produces a distinct class, each unique message mints its own Rollbar item. Messages routinely embed per-occurrence data (URLs, ids, CallStacks with package build hashes), so real-world deployments get one item per occurrence instead of one item per failure cause — we measured 135 items for ~2 causes in one 90-day export (iTrafficCenter/full-circle#3379).

Both library call sites are affected: withRollbar (Rollbar.Client) and the wai/yesod middleware (Rollbar.Wai).

Proposal

  • class = the concrete exception type name, e.g. via Data.Typeable (unwrapping SomeException first, since both call sites pass SomeException and typeOf would otherwise always yield "SomeException"):

    mkException :: E.Exception e => e -> Exception
    mkException e = Exception
      { exceptionClass = T.pack $ show $ typeOf inner
      , exceptionMessage = Just $ firstLine rendered
      , exceptionDescription = Just rendered
      }
      where
        SomeException inner = E.toException e
        rendered = T.pack $ E.displayException e
        firstLine = T.takeWhile (/= '\n')
  • message = first line of displayException; description = the full text, so no information is lost — it just stops living in the grouping key.

Related: empty frames

Both call sites send Trace [] …. Rollbar's default grouping for trace payloads is class + frames, so with the fix above all exceptions of one type collapse into a single item unless the reporting application sets an explicit fingerprint. The Frame type already exists but nothing populates it. Options worth exploring (possibly as a separate issue): an API for callers to supply frames, populating them from HasCallStack/ErrorCallWithLocation where available, or the exception backtraces available from GHC 9.10.

Breaking change

Any consumer relying on the current defaults will see all existing Rollbar items re-group once (new classes → new items) after upgrading. This warrants a major version bump and a release-notes warning.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions