Skip to content

[DO NOT MERGE] Add Sentry error tracking #1427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ next-env.d.ts

# versions
mise.toml

# Sentry config file
.env.sentry-build-plugin
26 changes: 26 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
/** @type {import('next').NextConfig} */

const nextConfig = {
output: "standalone",
distDir: "build",
basePath: process.env.NEXT_BASE_PATH || undefined,
};

module.exports = nextConfig;

// Sentry config
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { withSentryConfig } = require("@sentry/nextjs");

module.exports = withSentryConfig(module.exports, {
// For all available options, see:
// https://www.npmjs.com/package/@sentry/webpack-plugin#options

org: "stellarorg",
project: "labv2",

// Only print logs for uploading source maps in CI
silent: !process.env.CI,

// For all available options, see:
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/

// Automatically tree-shake Sentry logger statements to reduce bundle size
disableLogger: true,

reactComponentAnnotation: {
enabled: true,
},
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@ledgerhq/hw-app-str": "^7.2.0",
"@ledgerhq/hw-transport-webusb": "^6.29.4",
"@monaco-editor/react": "^4.7.0",
"@sentry/nextjs": "^9.22.0",
"@stellar/design-system": "^3.1.1",
"@stellar/stellar-sdk": "^13.0.0",
"@stellar/stellar-xdr-json": "^22.0.0-rc.1.1",
Expand Down
103 changes: 54 additions & 49 deletions src/app/error.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,65 @@
"use client";
import * as Sentry from "@sentry/nextjs";
import type { NextPage } from "next";
import type { ErrorProps } from "next/error";
import NextError from "next/error";

import { Button, Card, Heading, Icon, Text } from "@stellar/design-system";
import { Box } from "@/components/layout/Box";
import { LayoutContentContainer } from "@/components/layout/LayoutContentContainer";
import { openUrl } from "@/helpers/openUrl";

export default function Error({
error,
}: {
error: Error & { digest?: string };
}) {
// TODO: track this in Sentry once set up
console.log("Unhandled error: ", error);
const Error: NextPage<ErrorProps> = () => (
<LayoutContentContainer>
<Card>
<Box gap="xl" align="start">
<Box gap="md">
<Heading as="h2" size="xs" weight="medium">
Unhandled Error
</Heading>

return (
<LayoutContentContainer>
<Card>
<Box gap="xl" align="start">
<Box gap="md">
<Heading as="h2" size="xs" weight="medium">
Unhandled Error
</Heading>

<Text size="sm" as="p">
Uh-oh, we didn’t handle this error. We would appreciate it if you
opened an issue on GitHub, providing as many details as possible
to help us fix this bug.
</Text>
</Box>
<Text size="sm" as="p">
Uh-oh, we didn’t handle this error. We would appreciate it if you
opened an issue on GitHub, providing as many details as possible to
help us fix this bug.
</Text>
</Box>

<Box gap="md" direction="row">
<Button
size="sm"
variant="secondary"
icon={<Icon.ArrowLeft />}
iconPosition="left"
onClick={() => {
location.reload();
}}
>
Return
</Button>
<Box gap="md" direction="row">
<Button
size="sm"
variant="secondary"
icon={<Icon.ArrowLeft />}
iconPosition="left"
onClick={() => {
location.reload();
}}
>
Return
</Button>

<Button
size="sm"
variant="primary"
iconPosition="left"
onClick={() =>
openUrl("https://github.com/stellar/laboratory/issues")
}
>
Open Issue
</Button>
</Box>
<Button
size="sm"
variant="primary"
iconPosition="left"
onClick={() =>
openUrl("https://github.com/stellar/laboratory/issues")
}
>
Open Issue
</Button>
</Box>
</Card>
</LayoutContentContainer>
);
}
</Box>
</Card>
</LayoutContentContainer>
);

Error.getInitialProps = async (contextData) => {
// In case this is running in a serverless function, await this in order to give Sentry
// time to send the error before the lambda exits
await Sentry.captureUnderscoreErrorException(contextData);
// This will contain the status code of the response
return NextError.getInitialProps(contextData);
};

export default Error;
23 changes: 23 additions & 0 deletions src/app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client";

import * as Sentry from "@sentry/nextjs";
import NextError from "next/error";
import { useEffect } from "react";

export default function GlobalError({
error,
}: {
error: Error & { digest?: string };
}) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);

return (
<html>
<body>
<NextError statusCode={0} />
</body>
</html>
);
}
18 changes: 16 additions & 2 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ export default function Introduction() {
<LayoutContentContainer>
<PageCard heading="Stellar Lab">
<Text size="sm" as="p">
The Stellar Lab is an interactive toolkit for exploring the Stellar network. It helps developers and builders experiment with{" "}
The Stellar Lab is an interactive toolkit for exploring the Stellar
network. It helps developers and builders experiment with{" "}
<NextLink href={Routes.BUILD_TRANSACTION} sds-variant="primary">
building
</NextLink>
Expand All @@ -75,7 +76,10 @@ export default function Introduction() {
<NextLink href={Routes.SUBMIT_TRANSACTION} sds-variant="primary">
submitting transactions
</NextLink>
, as well as making requests to both RPC and Horizon APIs. With built-in tools for saving and sharing transactions, converting between XDR and JSON, and exploring smart contracts on Stellar, the Stellar Lab is ideal for testing, learning, and exploring on Stellar.
, as well as making requests to both RPC and Horizon APIs. With
built-in tools for saving and sharing transactions, converting between
XDR and JSON, and exploring smart contracts on Stellar, the Stellar
Lab is ideal for testing, learning, and exploring on Stellar.
</Text>

<Text size="sm" as="p">
Expand All @@ -87,6 +91,16 @@ export default function Introduction() {
</Text>
</PageCard>

{/*TODO: for testing; remove before merging */}
<button
type="button"
onClick={() => {
throw new Error("Test Sentry error");
}}
>
Trigger test error
</button>

<InfoCards infoCards={infoCards} />

<div className="IntroFooter">
Expand Down
42 changes: 42 additions & 0 deletions src/instrumentation-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Sentry
// This file configures the initialization of Sentry on the client.
// The added config here will be used whenever a users loads a page in their browser.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from "@sentry/nextjs";

Sentry.init({
dsn: "https://75c875528a113643f9a5f74899b53516@o14203.ingest.us.sentry.io/4508100110450688",
beforeSend: (event) => {
// We don't want to capture any sensitive info from the URL, so submitting
// only origin and pathname of the URL

// Referer header
if (event?.request?.headers?.Referer) {
try {
const { origin, pathname } = new URL(event.request.headers.Referer);
event.request.headers.Referer = `${origin}${pathname}`;
} catch {
// Do nothing
}
}

// URL field
if (event?.request?.url) {
try {
const { origin, pathname } = new URL(event.request.url);
event.request.url = `${origin}${pathname}`;
} catch {
// Do nothing
}
}

return event;
},
allowUrls: [
/^https?:\/\/[^/]+\.stellar\.org/,
/^https?:\/\/[^/]+\.stellar-ops\.com\//,
],
});

export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
Loading