Skip to main content

Sentry

Sentry is our primary observability tool for capturing and aggregating exceptions surfaced in our application. Engineers primarily interact with Sentry via the captureIssue helper, which standardizes and decorates caught errors prior to sending them to Sentry. Sentry provides support for multiple environments, of which we configure to match the application's current runtime via Sentry's environment config.

You can find our Sentry dashboard here: birdy-grey-eng on Sentry

Automatic Exception Capturingโ€‹

Sentry's SDK offers automatic exception capturing for React Router, which automatically detects thrown errors in our route handlers as well as in the client browser. Our GTM implementation pulls in a lot of third party code, so we are leveraging Sentry's third party error filter integration to only flag JavaScript frames that are sourced from our codebase.

Manually Capturing Exceptionsโ€‹

Sentry's bread and butter is its captureException function, which accepts an Error or message and enriches it with contextual information from the user's session prior to sending the event to Sentry. Instead of calling captureException directly, we primarily interact with it via our captureIssue proxy, which provides standardized arguments for passing in enriched data. The recommended flow for capturing exceptions is as follows:

  1. When an exception is caught, surface the JavaScript Error or create a new Error at the time in which the error was thrown
  2. Identify high cardinality values that would be shared across multiple issues, including the one being thrown. These indexable values will be passed as tags.
  3. If the stacktrace in the original Error is insufficient, identify any supplemental, instance-specific metadata to include. These values (not indexable) will be passed as additional contexts.
  4. Call captureIssue and specify the severity of the issue (Error by default) and pass any tags or contexts with the Error.

Sentry automatically captures information about the session and user (if available) and embeds this data into the collected exception.

When should I use captureIssue vs captureLog?โ€‹

A common question engineers have is when to reach for captureIssue versus captureLog. Both helper functions have similar function signatures and pass through Sentry's SDK, but there are distinctions to the behavior of both. Generally you can ask the following questions:

What's the severity of the issue?โ€‹

For issues impacting the customer shopping experience, use captureIssue. Sentry offers a convenient platform for surfacing issues impacting the client experience, coupled with issue grouping, replays, and automatic context collection. Pass along an Error object to get a sourcemapped stack trace.

For lower severity issues (ones that we should fix but do not require immediate attention), you can still use captureIssue with an adjusted severity level argument.

For supplemental or informational logging that could provide hints for additional debugging and does not warrant immediate triage, reach for captureLog.

How frequently would this log fire?โ€‹

For high volume logs, prefer using captureLog. Cloud Logging does not have the same bandwidth limits as Sentry Issues, so lower severity + higher volume logs are a better fit for the Log Drain. Logs that fire during a React component render cycle are often higher volume, so we need to exercise caution with these types of logs. Sentry does offer basic dedupe logic, but flooding the Sentry ingest is probably not a great idea either.

For logs where frequency spikes are a strong indicator of affliction, captureLog is likely a better fit as we can more easily visualize for patterns over time.

What kind of data do I want to log?โ€‹

Most of the time, handling a JavaScript Error points to using captureIssue. Sentry offers first-party support for stacktrace viewing with sourcemapped files. Of course, if the Error object doesn't provide much guidance, it may make more sense to craft a custom Error and capture accordingly.

Our Log Drain allows for enriching application logs with additional metadata, but generally these values should be simple strings or numbers.

Sentry Loggingโ€‹

We route all of our application logs through the captureLog helper, which allows us to provide a standardized API for logging to either standard our or Sentry. It also allows us to control the sample rate similar to other Sentry configurations.

Here's how it works:

captureLog accepts the log input and sends it to the Sentry Logger SDK. From there, depending on the runtime, we have different configurations for Sentry's logging behavior.

For server logs, the beforeServerSendLog callback applies sampling logic and if the log is sampled, it parses it, prints it to standard out, and then returns null to drop the log before it is sent to Sentry. Standard out will be processed by the Log Drain and then forwarded to Cloud Logging.

For client logs, the beforeSendLog callback applies the same sampling logic and if the log is sampled, it sends it to Sentry.