Introduce error boundary mechanism and exception capture with Baselime and Sentry
Deleted the ErrorBoundary component from the makerkit package and introduced new exception capture mechanisms for Baselime and Sentry monitoring providers. The code now captures all exceptions thrown within components and sends them to the configured monitoring provider, which in turn logs the errors for debugging purposes. Updated packages and environment variables accordingly to support this feature.
This commit is contained in:
@@ -45,3 +45,7 @@ NEXT_PUBLIC_ENABLE_ACCOUNT_DELETION=true
|
||||
NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING=true
|
||||
NEXT_PUBLIC_ENABLE_ORGANIZATION_DELETION=true
|
||||
NEXT_PUBLIC_ENABLE_ORGANIZATION_BILLING=true
|
||||
|
||||
# MONITORING
|
||||
MONITORING_PROVIDER=
|
||||
MONITORING_INSTRUMENTATION_ENABLED=false
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { ExclamationTriangleIcon } from '@radix-ui/react-icons';
|
||||
|
||||
import { useCaptureException } from '@kit/monitoring/hooks';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { PageBody, PageHeader } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
export default function BillingErrorPage() {
|
||||
const router = useRouter();
|
||||
export default function BillingErrorPage({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) {
|
||||
useCaptureException(error);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -34,7 +39,7 @@ export default function BillingErrorPage() {
|
||||
</Alert>
|
||||
|
||||
<div>
|
||||
<Button variant={'outline'} onClick={() => router.refresh()}>
|
||||
<Button variant={'outline'} onClick={reset}>
|
||||
<Trans i18nKey={'common:retry'} />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -4,13 +4,22 @@ import Link from 'next/link';
|
||||
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
|
||||
import { useCaptureException } from '@kit/monitoring/hooks';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { Heading } from '@kit/ui/heading';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { SiteHeader } from '~/(marketing)/_components/site-header';
|
||||
|
||||
const ErrorPage = () => {
|
||||
const ErrorPage = ({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) => {
|
||||
useCaptureException(error);
|
||||
|
||||
return (
|
||||
<div className={'flex h-screen flex-1 flex-col'}>
|
||||
<SiteHeader />
|
||||
@@ -39,13 +48,11 @@ const ErrorPage = () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href={'/'}>
|
||||
<Button variant={'outline'}>
|
||||
<Button variant={'outline'} onClick={reset}>
|
||||
<ArrowLeft className={'mr-2 h-4'} />
|
||||
|
||||
<Trans i18nKey={'common:backToHomePage'} />
|
||||
<Trans i18nKey={'common:goBack'} />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
* This file is used to register monitoring instrumentation
|
||||
* for your Next.js application.
|
||||
*/
|
||||
|
||||
const RUNTIME = process.env.NEXT_RUNTIME;
|
||||
|
||||
const ENABLE_INSTRUMENTATION =
|
||||
process.env.MONITORING_INSTRUMENTATION_ENABLED === 'true';
|
||||
|
||||
export async function register() {
|
||||
// only run in nodejs runtime
|
||||
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
||||
if (RUNTIME === 'nodejs' && ENABLE_INSTRUMENTATION) {
|
||||
const { registerMonitoringInstrumentation } = await import(
|
||||
'@kit/monitoring'
|
||||
'@kit/monitoring/instrumentation'
|
||||
);
|
||||
|
||||
// Register monitoring instrumentation based on the
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"clear": "Clear",
|
||||
"notFound": "Not Found",
|
||||
"backToHomePage": "Back to Home Page",
|
||||
"goBack": "Go Back",
|
||||
"genericServerError": "Sorry, something went wrong.",
|
||||
"genericServerErrorHeading": "Sorry, something went wrong while processing your request. Please contact us if the issue persists.",
|
||||
"pageNotFound": "Sorry, this page does not exist.",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"@kit/email-templates": "workspace:^",
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/mailers": "workspace:^",
|
||||
"@kit/monitoring": "workspace:^",
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/shared": "workspace:^",
|
||||
"@kit/supabase": "workspace:^",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { ExclamationTriangleIcon } from '@radix-ui/react-icons';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { ErrorBoundary } from '@kit/monitoring/components';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||
import {
|
||||
AlertDialog,
|
||||
@@ -17,7 +18,6 @@ import {
|
||||
AlertDialogTrigger,
|
||||
} from '@kit/ui/alert-dialog';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { ErrorBoundary } from '@kit/ui/error-boundary';
|
||||
import { Form, FormControl, FormItem, FormLabel } from '@kit/ui/form';
|
||||
import { Input } from '@kit/ui/input';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"@kit/email-templates": "workspace:^",
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/mailers": "workspace:^",
|
||||
"@kit/monitoring": "workspace:*",
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/shared": "workspace:^",
|
||||
"@kit/supabase": "workspace:^",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ErrorBoundary } from '@kit/monitoring/components';
|
||||
import { useUser } from '@kit/supabase/hooks/use-user';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||
import {
|
||||
@@ -19,7 +20,6 @@ import {
|
||||
AlertDialogTrigger,
|
||||
} from '@kit/ui/alert-dialog';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { ErrorBoundary } from '@kit/ui/error-boundary';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
},
|
||||
"prettier": "@kit/prettier-config",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
".": "./src/index.ts",
|
||||
"./instrumentation": "./src/instrumentation.ts",
|
||||
"./provider": "./src/components/provider.tsx"
|
||||
},
|
||||
"dependencies": {
|
||||
"@baselime/node-opentelemetry": "^0.5.8"
|
||||
"@baselime/node-opentelemetry": "^0.5.8",
|
||||
"@baselime/react-rum": "^0.2.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
|
||||
4
packages/monitoring/baselime/src/capture-exception.ts
Normal file
4
packages/monitoring/baselime/src/capture-exception.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export function captureException(error: Error) {
|
||||
console.info(`No yet defined...`);
|
||||
return console.error(`Caught exception: ${JSON.stringify(error)}`);
|
||||
}
|
||||
22
packages/monitoring/baselime/src/components/provider.tsx
Normal file
22
packages/monitoring/baselime/src/components/provider.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { BaselimeRum } from '@baselime/react-rum';
|
||||
|
||||
export function BaselineProvider({
|
||||
children,
|
||||
apiKey,
|
||||
enableWebVitals,
|
||||
ErrorPage,
|
||||
}: React.PropsWithChildren<{
|
||||
apiKey: string;
|
||||
enableWebVitals?: boolean;
|
||||
ErrorPage?: React.ReactElement;
|
||||
}>) {
|
||||
return (
|
||||
<BaselimeRum
|
||||
apiKey={apiKey}
|
||||
enableWebVitals={enableWebVitals}
|
||||
fallback={ErrorPage ?? null}
|
||||
>
|
||||
{children}
|
||||
</BaselimeRum>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useBaselimeRum } from '@baselime/react-rum';
|
||||
|
||||
export function useCaptureException() {
|
||||
const { captureException } = useBaselimeRum();
|
||||
|
||||
return useCallback(
|
||||
(error: Error) => captureException(error),
|
||||
[captureException],
|
||||
);
|
||||
}
|
||||
@@ -1,31 +1 @@
|
||||
const INSTRUMENTATION_SERVICE_NAME = process.env.INSTRUMENTATION_SERVICE_NAME;
|
||||
|
||||
if (!INSTRUMENTATION_SERVICE_NAME) {
|
||||
throw new Error(`
|
||||
You have set the Baselime instrumentation provider, but have not set the INSTRUMENTATION_SERVICE_NAME environment variable. Please set the INSTRUMENTATION_SERVICE_NAME environment variable.
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name registerBaselimeInstrumentation
|
||||
* @description This file is used to register Baselime instrumentation for your Next.js application.
|
||||
*
|
||||
* Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to 'baselime' to register Baselime instrumentation.
|
||||
*/
|
||||
export async function registerBaselimeInstrumentation() {
|
||||
const { BaselimeSDK, BetterHttpInstrumentation, VercelPlugin } = await import(
|
||||
'@baselime/node-opentelemetry'
|
||||
);
|
||||
|
||||
const sdk = new BaselimeSDK({
|
||||
serverless: true,
|
||||
service: INSTRUMENTATION_SERVICE_NAME,
|
||||
instrumentations: [
|
||||
new BetterHttpInstrumentation({
|
||||
plugins: [new VercelPlugin()],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
sdk.start();
|
||||
}
|
||||
export * from './capture-exception';
|
||||
|
||||
31
packages/monitoring/baselime/src/instrumentation.ts
Normal file
31
packages/monitoring/baselime/src/instrumentation.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
const INSTRUMENTATION_SERVICE_NAME = process.env.INSTRUMENTATION_SERVICE_NAME;
|
||||
|
||||
if (!INSTRUMENTATION_SERVICE_NAME) {
|
||||
throw new Error(`
|
||||
You have set the Baselime instrumentation provider, but have not set the INSTRUMENTATION_SERVICE_NAME environment variable. Please set the INSTRUMENTATION_SERVICE_NAME environment variable.
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name registerBaselimeInstrumentation
|
||||
* @description This file is used to register Baselime instrumentation for your Next.js application.
|
||||
*
|
||||
* Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to 'baselime' to register Baselime instrumentation.
|
||||
*/
|
||||
export async function registerBaselimeInstrumentation() {
|
||||
const { BaselimeSDK, BetterHttpInstrumentation, VercelPlugin } = await import(
|
||||
'@baselime/node-opentelemetry'
|
||||
);
|
||||
|
||||
const sdk = new BaselimeSDK({
|
||||
serverless: true,
|
||||
service: INSTRUMENTATION_SERVICE_NAME,
|
||||
instrumentations: [
|
||||
new BetterHttpInstrumentation({
|
||||
plugins: [new VercelPlugin()],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
sdk.start();
|
||||
}
|
||||
@@ -11,7 +11,10 @@
|
||||
},
|
||||
"prettier": "@kit/prettier-config",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
".": "./src/index.ts",
|
||||
"./instrumentation": "./src/instrumentation.ts",
|
||||
"./hooks": "./src/hooks/index.ts",
|
||||
"./components": "./src/components/index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kit/baselime": "workspace:*",
|
||||
@@ -19,7 +22,12 @@
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/sentry": "workspace:*",
|
||||
"@kit/tailwind-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*"
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@types/react": "^18.2.77",
|
||||
"react": "18.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"prettier": "@kit/prettier-config",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./instrumentation": "./src/instrumentation.ts",
|
||||
"./config/client": "./src/config/sentry.client.config.ts",
|
||||
"./config/server": "./src/config/sentry.server.config.ts",
|
||||
"./config/edge": "./src/config/sentry.server.edge.ts"
|
||||
|
||||
5
packages/monitoring/sentry/src/capture-exception.ts
Normal file
5
packages/monitoring/sentry/src/capture-exception.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
export function captureException(error: Error & { digest?: string }) {
|
||||
return Sentry.captureException(error);
|
||||
}
|
||||
@@ -1,36 +1 @@
|
||||
const INSTRUMENTATION_SERVICE_NAME = process.env.INSTRUMENTATION_SERVICE_NAME;
|
||||
|
||||
if (!INSTRUMENTATION_SERVICE_NAME) {
|
||||
throw new Error(`
|
||||
You have set the Sentry instrumentation provider, but have not set the INSTRUMENTATION_SERVICE_NAME environment variable. Please set the INSTRUMENTATION_SERVICE_NAME environment variable.
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name registerSentryInstrumentation
|
||||
* @description This file is used to register Sentry instrumentation for your Next.js application.
|
||||
*
|
||||
* Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to 'sentry' to register Sentry instrumentation.
|
||||
*/
|
||||
export async function registerSentryInstrumentation() {
|
||||
const { Resource } = await import('@opentelemetry/resources');
|
||||
const { NodeSDK } = await import('@opentelemetry/sdk-node');
|
||||
|
||||
const { SEMRESATTRS_SERVICE_NAME } = await import(
|
||||
'@opentelemetry/semantic-conventions'
|
||||
);
|
||||
|
||||
const { SentrySpanProcessor, SentryPropagator } = await import(
|
||||
'@sentry/opentelemetry-node'
|
||||
);
|
||||
|
||||
const sdk = new NodeSDK({
|
||||
resource: new Resource({
|
||||
[SEMRESATTRS_SERVICE_NAME]: INSTRUMENTATION_SERVICE_NAME,
|
||||
}),
|
||||
spanProcessor: new SentrySpanProcessor(),
|
||||
textMapPropagator: new SentryPropagator(),
|
||||
});
|
||||
|
||||
sdk.start();
|
||||
}
|
||||
export { captureException } from './capture-exception';
|
||||
|
||||
36
packages/monitoring/sentry/src/instrumentation.ts
Normal file
36
packages/monitoring/sentry/src/instrumentation.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
const INSTRUMENTATION_SERVICE_NAME = process.env.INSTRUMENTATION_SERVICE_NAME;
|
||||
|
||||
if (!INSTRUMENTATION_SERVICE_NAME) {
|
||||
throw new Error(`
|
||||
You have set the Sentry instrumentation provider, but have not set the INSTRUMENTATION_SERVICE_NAME environment variable. Please set the INSTRUMENTATION_SERVICE_NAME environment variable.
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name registerSentryInstrumentation
|
||||
* @description This file is used to register Sentry instrumentation for your Next.js application.
|
||||
*
|
||||
* Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to 'sentry' to register Sentry instrumentation.
|
||||
*/
|
||||
export async function registerSentryInstrumentation() {
|
||||
const { Resource } = await import('@opentelemetry/resources');
|
||||
const { NodeSDK } = await import('@opentelemetry/sdk-node');
|
||||
|
||||
const { SEMRESATTRS_SERVICE_NAME } = await import(
|
||||
'@opentelemetry/semantic-conventions'
|
||||
);
|
||||
|
||||
const { SentrySpanProcessor, SentryPropagator } = await import(
|
||||
'@sentry/opentelemetry-node'
|
||||
);
|
||||
|
||||
const sdk = new NodeSDK({
|
||||
resource: new Resource({
|
||||
[SEMRESATTRS_SERVICE_NAME]: INSTRUMENTATION_SERVICE_NAME,
|
||||
}),
|
||||
spanProcessor: new SentrySpanProcessor(),
|
||||
textMapPropagator: new SentryPropagator(),
|
||||
});
|
||||
|
||||
sdk.start();
|
||||
}
|
||||
44
packages/monitoring/src/capture-exception.ts
Normal file
44
packages/monitoring/src/capture-exception.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { InstrumentationProvider } from './monitoring-providers.enum';
|
||||
|
||||
/**
|
||||
* @name MONITORING_PROVIDER
|
||||
* @description Register monitoring instrumentation based on the MONITORING_PROVIDER environment variable.
|
||||
*/
|
||||
const MONITORING_PROVIDER = process.env.MONITORING_PROVIDER as
|
||||
| InstrumentationProvider
|
||||
| undefined;
|
||||
|
||||
/**
|
||||
* @name captureException
|
||||
* @description Capture an exception and send it to the monitoring provider defined.
|
||||
* @param error
|
||||
*/
|
||||
export async function captureException(error: Error) {
|
||||
if (!MONITORING_PROVIDER) {
|
||||
console.info(
|
||||
`No instrumentation provider specified. Logging to console...`,
|
||||
);
|
||||
|
||||
return console.error(`Caught exception: ${JSON.stringify(error)}`);
|
||||
}
|
||||
|
||||
switch (MONITORING_PROVIDER) {
|
||||
case InstrumentationProvider.Baselime: {
|
||||
const { captureException } = await import('@kit/baselime');
|
||||
|
||||
return captureException(error);
|
||||
}
|
||||
|
||||
case InstrumentationProvider.Sentry: {
|
||||
const { captureException } = await import('@kit/sentry');
|
||||
|
||||
return captureException(error);
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new Error(
|
||||
`Please set the MONITORING_PROVIDER environment variable to register the monitoring instrumentation provider.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
39
packages/monitoring/src/components/error-boundary.tsx
Normal file
39
packages/monitoring/src/components/error-boundary.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { ErrorInfo, ReactNode } from 'react';
|
||||
import { Component } from 'react';
|
||||
|
||||
import { captureException } from '../capture-exception';
|
||||
|
||||
interface Props {
|
||||
onError?: (error: Error, info: ErrorInfo) => void;
|
||||
fallback: ReactNode;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export class ErrorBoundary extends Component<Props> {
|
||||
readonly state = { hasError: false, error: null };
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: unknown) {
|
||||
return {
|
||||
hasError: true,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidCatch(error: Error, info: ErrorInfo) {
|
||||
this.props.onError?.(error, info);
|
||||
|
||||
await captureException(error);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return this.props.fallback;
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
1
packages/monitoring/src/components/index.ts
Normal file
1
packages/monitoring/src/components/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './error-boundary';
|
||||
1
packages/monitoring/src/hooks/index.ts
Normal file
1
packages/monitoring/src/hooks/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './use-capture-exception';
|
||||
11
packages/monitoring/src/hooks/use-capture-exception.ts
Normal file
11
packages/monitoring/src/hooks/use-capture-exception.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { captureException } from '../capture-exception';
|
||||
|
||||
export function useCaptureException(error: Error) {
|
||||
useEffect(() => {
|
||||
void captureException(error);
|
||||
}, [error]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
export * from './instrumentation';
|
||||
export * from './capture-exception';
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
enum InstrumentationProvider {
|
||||
Baselime = 'baselime',
|
||||
Sentry = 'sentry',
|
||||
}
|
||||
import { InstrumentationProvider } from './monitoring-providers.enum';
|
||||
|
||||
/**
|
||||
* @name DEFAULT_INSTRUMENTATION_PROVIDER
|
||||
* @description Register monitoring instrumentation based on the MONITORING_INSTRUMENTATION_PROVIDER environment variable.
|
||||
* @name MONITORING_PROVIDER
|
||||
* @description Register monitoring instrumentation based on the MONITORING_PROVIDER environment variable.
|
||||
*/
|
||||
const DEFAULT_INSTRUMENTATION_PROVIDER = process.env
|
||||
.MONITORING_INSTRUMENTATION_PROVIDER as InstrumentationProvider | undefined;
|
||||
const MONITORING_PROVIDER = process.env.MONITORING_PROVIDER as
|
||||
| InstrumentationProvider
|
||||
| undefined;
|
||||
|
||||
/**
|
||||
* @name registerMonitoringInstrumentation
|
||||
* @description Register monitoring instrumentation based on the MONITORING_INSTRUMENTATION_PROVIDER environment variable.
|
||||
* @description Register monitoring instrumentation based on the MONITORING_PROVIDER environment variable.
|
||||
*
|
||||
* Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to register the monitoring instrumentation provider.
|
||||
* Please set the MONITORING_PROVIDER environment variable to register the monitoring instrumentation provider.
|
||||
*/
|
||||
export async function registerMonitoringInstrumentation() {
|
||||
if (!DEFAULT_INSTRUMENTATION_PROVIDER) {
|
||||
if (!MONITORING_PROVIDER) {
|
||||
console.info(`No instrumentation provider specified. Skipping...`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (DEFAULT_INSTRUMENTATION_PROVIDER) {
|
||||
switch (MONITORING_PROVIDER) {
|
||||
case InstrumentationProvider.Baselime: {
|
||||
const { registerBaselimeInstrumentation } = await import('@kit/baselime');
|
||||
const { registerBaselimeInstrumentation } = await import(
|
||||
'@kit/baselime/instrumentation'
|
||||
);
|
||||
|
||||
return registerBaselimeInstrumentation();
|
||||
}
|
||||
|
||||
case InstrumentationProvider.Sentry: {
|
||||
const { registerSentryInstrumentation } = await import('@kit/sentry');
|
||||
const { registerSentryInstrumentation } = await import(
|
||||
'@kit/sentry/instrumentation'
|
||||
);
|
||||
|
||||
return registerSentryInstrumentation();
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown instrumentation provider: ${DEFAULT_INSTRUMENTATION_PROVIDER as string}`,
|
||||
`Unknown instrumentation provider: ${MONITORING_PROVIDER as string}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
4
packages/monitoring/src/monitoring-providers.enum.ts
Normal file
4
packages/monitoring/src/monitoring-providers.enum.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum InstrumentationProvider {
|
||||
Baselime = 'baselime',
|
||||
Sentry = 'sentry',
|
||||
}
|
||||
@@ -119,7 +119,6 @@
|
||||
"./page": "./src/makerkit/page.tsx",
|
||||
"./image-uploader": "./src/makerkit/image-uploader.tsx",
|
||||
"./global-loader": "./src/makerkit/global-loader.tsx",
|
||||
"./error-boundary": "./src/makerkit/error-boundary.tsx",
|
||||
"./auth-change-listener": "./src/makerkit/auth-change-listener.tsx",
|
||||
"./loading-overlay": "./src/makerkit/loading-overlay.tsx",
|
||||
"./profile-avatar": "./src/makerkit/profile-avatar.tsx",
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
import { Component } from 'react';
|
||||
|
||||
export class ErrorBoundary extends Component<{
|
||||
fallback: ReactNode;
|
||||
children: ReactNode;
|
||||
}> {
|
||||
readonly state = { hasError: false, error: null };
|
||||
|
||||
static getDerivedStateFromError(error: unknown) {
|
||||
return {
|
||||
hasError: true,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return this.props.fallback;
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
39
pnpm-lock.yaml
generated
39
pnpm-lock.yaml
generated
@@ -554,6 +554,9 @@ importers:
|
||||
'@kit/mailers':
|
||||
specifier: workspace:^
|
||||
version: link:../../mailers
|
||||
'@kit/monitoring':
|
||||
specifier: workspace:^
|
||||
version: link:../../monitoring
|
||||
'@kit/prettier-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/prettier
|
||||
@@ -759,6 +762,9 @@ importers:
|
||||
'@kit/mailers':
|
||||
specifier: workspace:^
|
||||
version: link:../../mailers
|
||||
'@kit/monitoring':
|
||||
specifier: workspace:*
|
||||
version: link:../../monitoring
|
||||
'@kit/prettier-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/prettier
|
||||
@@ -901,12 +907,21 @@ importers:
|
||||
'@kit/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:../../tooling/typescript
|
||||
'@types/react':
|
||||
specifier: ^18.2.77
|
||||
version: 18.2.78
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
|
||||
packages/monitoring/baselime:
|
||||
dependencies:
|
||||
'@baselime/node-opentelemetry':
|
||||
specifier: ^0.5.8
|
||||
version: 0.5.8(@trpc/server@10.45.2)
|
||||
'@baselime/react-rum':
|
||||
specifier: ^0.2.9
|
||||
version: 0.2.9(react@18.2.0)
|
||||
devDependencies:
|
||||
'@kit/eslint-config':
|
||||
specifier: workspace:*
|
||||
@@ -1584,6 +1599,17 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@baselime/react-rum@0.2.9(react@18.2.0):
|
||||
resolution: {integrity: sha512-x5+eYsNCsasHD6jbfH02HmwA7i8A+3Ac3PS2tKwgFgoqi1EmIgktjAvdYFosTZe73VIQMal19peRXAu2/lGxAA==}
|
||||
peerDependencies:
|
||||
react: ^18.2.0
|
||||
dependencies:
|
||||
js-cookie: 3.0.5
|
||||
react: 18.2.0
|
||||
react-error-boundary: 4.0.13(react@18.2.0)
|
||||
web-vitals: 3.5.2
|
||||
dev: false
|
||||
|
||||
/@braintree/sanitize-url@6.0.4:
|
||||
resolution: {integrity: sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==}
|
||||
dev: false
|
||||
@@ -11690,6 +11716,15 @@ packages:
|
||||
- webpack-cli
|
||||
dev: false
|
||||
|
||||
/react-error-boundary@4.0.13(react@18.2.0):
|
||||
resolution: {integrity: sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==}
|
||||
peerDependencies:
|
||||
react: '>=16.13.1'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.4
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-hook-form@7.51.3(react@18.2.0):
|
||||
resolution: {integrity: sha512-cvJ/wbHdhYx8aviSWh28w9ImjmVsb5Y05n1+FW786vEZQJV5STNM0pW6ujS+oiBecb0ARBxJFyAnXj9+GHXACQ==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
@@ -13296,6 +13331,10 @@ packages:
|
||||
engines: {node: '>= 8'}
|
||||
dev: true
|
||||
|
||||
/web-vitals@3.5.2:
|
||||
resolution: {integrity: sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==}
|
||||
dev: false
|
||||
|
||||
/webidl-conversions@3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user