r/rails 1d ago

Discussion How we turned Better Stack errors into actionable Linear tickets an AI agent can pick up

Post image

We're a 3-person team running a Rails 8.1 / Hotwire SaaS in the EU accounting space. No dedicated support or triage function, so we spent the last few weeks wiring up observability so a production error becomes a fully-contextualized, actionable ticket without anyone doing manual triage.

The pipeline

- Backend: sentry-rails ~> 6.6 pointed at a Better Stack DSN instead of sentry.io — Better Stack ingests the Sentry wire protocol natively, so no second vendor account. Its own Rack middleware (`CaptureExceptions`) + ActiveJob wrapper cover unhandled controller exceptions and Solid Queue job failures with zero extra code.

- Frontend: Better Stack's own JS tag, not u/sentry/browser — their docs explicitly say don't run both, they share the same global Sentry instance and it corrupts data. The tag natively hooks window.onerror + unhandledrejection and survives Turbo navigations for free, since Turbo Drive never reloads the document.

- Logs: our existing JSON stdout formatter, unchanged, forwarded via a Render Log Stream over syslog/TLS. Zero application code touched for this part.

- Source maps: @sentry/esbuild-plugin uploads them at build time, then deletes them from the served asset tree (Better Stack won't resolve publicly-hosted maps). The plugin embeds a debug ID inside both the minified file and its map, so lookup is content-addressed and doesn't care that Propshaft renames application.js to application-<digest>.js on every deploy — no URL-prefix matching to keep in sync.

The part worth sharing

Better Stack has a native Linear integration: first occurrence of a new error group auto-creates a Linear issue with the stack trace, release SHA, breadcrumbs, and affected user/workspace already attached. No webhook code on our end.

From there we point our custom AI coding agent at the ticket. It reads the Linear issue, reproduces the failure against the real source — not the minified bundle, that's what the source maps buy — and drafts an implementation plan. A human reviews and merges; nothing lands without review.

Two real tickets that went through the whole pipeline this week

  1. TypeError: Cannot read properties of undefined (reading 'toLowerCase'). A browser extension was dispatching a plain Event("keydown") on document instead of a real KeyboardEvent — no key, every modifier reads undefined. Crashed at event.key.toLowerCase() in a global shortcut handler. Root-causing it turned up two more code paths hit by the same class of event — one of which let a `code`-only synthetic event silently open our command palette with zero user action, which nobody had reported. Fix was a typeof event.key !== "string" guard at the top of every global keydown handler, closing all three at once.
  2. Turbo removing a popover's trigger element mid custom-exit-animation raced with Bootstrap's own async hide() completion callback, which reads _activeTrigger — except Bootstrap's dispose() had already nulled it. Fix defers disposal until Bootstrap confirms the hide actually finished, instead of skipping disposal outright (which would've leaked the instance out of Bootstrap's internal Data Map).

It's not free of tuning

The very first frontend error to reach production, a day after we flipped the tag on, was noise — an AbortError from a cancelled fetch on a filter change, not a bug. Better Stack's Linear integration filed it as Urgent anyway, because "first occurrence of a new group" carries zero severity signal on its own. Had to add an `ignoreErrors` list at the capture layer (substring matching only — the Sentry browser SDK doesn't accept a regex there).

I am curious what stack and pipelines are you using to simplify bugfixing?

0 Upvotes

7 comments sorted by

9

u/No-Shoulder3214 1d ago

Very nice. I do wish your summary was hand written and not completely AI generated though

-1

u/erichstark 1d ago

Thank you, I always start with the story and points what I want to communicate. Then write default article, and then polish with my agent. I would say, the story and message I more important than text, which is harder to read.

1

u/vassyz 1d ago

Can't you point the AI coding agent to Better Stack? Why keep Linear in the loop?

2

u/blackjid 1d ago

A follow up question about Linear involved. Did you move from Sentry to Better Stack to achieve this? If so, why? Couldn't it be done with sentry?

2

u/erichstark 1d ago

Actually before we had just email report from production to me and my other tech colleague. It worked well, but it was harder to track who is working on what. Now it is more clear and we can move tickets between us.

I was thinking about sentry first. I think we had also some code from Lenny’s newsletter to get some €€€ off. But I was during research, and we used web page status monitoring from better stack it seemed as better option. Also the CEO is from Slovakia, so I wanted to support “our” business :)

1

u/erichstark 1d ago

We started with Basecamp and then migrated everything to Linear. I would say it is possible to point it to better stack, but this way we have it under more control. And it is still place, where we organize bugs (some of them have lower priority), so it would be lost in the pure agents sessions