Refactor monitoring package and improve error handling
The monitoring package has been significantly refactored to improve the granularity of error capture. Code from the 'capture-exception.ts' files in different locations have been deleted and replaced by a more unified approach in the 'use-baselime.ts' and 'use-sentry.ts' hooks. The README documentation has also been updated to reflect these changes and provide additional information about error monitoring setup and usage.
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
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.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
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;
|
||||
@@ -23,10 +21,8 @@ export class ErrorBoundary extends Component<Props> {
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidCatch(error: Error, info: ErrorInfo) {
|
||||
componentDidCatch(error: Error, info: ErrorInfo) {
|
||||
this.props.onError?.(error, info);
|
||||
|
||||
await captureException(error);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
7
packages/monitoring/src/get-monitoring-provider.ts
Normal file
7
packages/monitoring/src/get-monitoring-provider.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { InstrumentationProvider } from './monitoring-providers.enum';
|
||||
|
||||
export function getMonitoringProvider() {
|
||||
return process.env.NEXT_PUBLIC_MONITORING_PROVIDER as
|
||||
| InstrumentationProvider
|
||||
| undefined;
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export * from './use-monitoring';
|
||||
export * from './use-capture-exception';
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { captureException } from '../capture-exception';
|
||||
import { useMonitoring } from './use-monitoring';
|
||||
|
||||
export function useCaptureException(error: Error) {
|
||||
useEffect(() => {
|
||||
void captureException(error);
|
||||
}, [error]);
|
||||
const service = useMonitoring();
|
||||
|
||||
return null;
|
||||
return service.captureException(error);
|
||||
}
|
||||
|
||||
51
packages/monitoring/src/hooks/use-monitoring.ts
Normal file
51
packages/monitoring/src/hooks/use-monitoring.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { getMonitoringProvider } from '../get-monitoring-provider';
|
||||
import { InstrumentationProvider } from '../monitoring-providers.enum';
|
||||
import { ConsoleMonitoringService } from '../services/console-monitoring.service';
|
||||
import { MonitoringService } from '../services/monitoring.service';
|
||||
|
||||
const MONITORING = getMonitoringProvider();
|
||||
|
||||
let service: MonitoringService;
|
||||
|
||||
/**
|
||||
* @name useMonitoring
|
||||
* @description Asynchronously load the monitoring service based on the MONITORING_PROVIDER environment variable.
|
||||
* Use Suspense to suspend while loading the service.
|
||||
*/
|
||||
export function useMonitoring() {
|
||||
if (!service) {
|
||||
throw withMonitoringService();
|
||||
}
|
||||
|
||||
console.log(service);
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
async function withMonitoringService() {
|
||||
service = await loadMonitoringService();
|
||||
}
|
||||
|
||||
async function loadMonitoringService() {
|
||||
if (!MONITORING) {
|
||||
return new ConsoleMonitoringService();
|
||||
}
|
||||
|
||||
switch (MONITORING) {
|
||||
case InstrumentationProvider.Baselime: {
|
||||
const { useBaselime } = await import('@kit/baselime/client');
|
||||
|
||||
return useBaselime;
|
||||
}
|
||||
|
||||
case InstrumentationProvider.Sentry: {
|
||||
const { useSentry } = await import('@kit/sentry/client');
|
||||
|
||||
return useSentry;
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new Error(`Unknown instrumentation provider: ${MONITORING}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from './capture-exception';
|
||||
@@ -1,5 +1,8 @@
|
||||
import { getMonitoringProvider } from './get-monitoring-provider';
|
||||
import { InstrumentationProvider } from './monitoring-providers.enum';
|
||||
|
||||
const PROVIDER = getMonitoringProvider();
|
||||
|
||||
/**
|
||||
* @name registerMonitoringInstrumentation
|
||||
* @description Register monitoring instrumentation based on the MONITORING_PROVIDER environment variable.
|
||||
@@ -7,13 +10,13 @@ import { InstrumentationProvider } from './monitoring-providers.enum';
|
||||
* Please set the MONITORING_PROVIDER environment variable to register the monitoring instrumentation provider.
|
||||
*/
|
||||
export async function registerMonitoringInstrumentation() {
|
||||
if (!process.env.MONITORING_PROVIDER) {
|
||||
if (!PROVIDER) {
|
||||
console.info(`No instrumentation provider specified. Skipping...`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (process.env.MONITORING_PROVIDER as InstrumentationProvider) {
|
||||
switch (PROVIDER) {
|
||||
case InstrumentationProvider.Baselime: {
|
||||
const { registerInstrumentation } = await import(
|
||||
'@kit/baselime/instrumentation'
|
||||
|
||||
1
packages/monitoring/src/server.ts
Normal file
1
packages/monitoring/src/server.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './services/get-server-monitoring-service';
|
||||
@@ -0,0 +1,11 @@
|
||||
import { MonitoringService } from './monitoring.service';
|
||||
|
||||
export class ConsoleMonitoringService implements MonitoringService {
|
||||
identifyUser() {
|
||||
// noop
|
||||
}
|
||||
|
||||
captureException(error: Error) {
|
||||
console.error(`Caught exception: ${JSON.stringify(error)}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { getMonitoringProvider } from '../get-monitoring-provider';
|
||||
import { InstrumentationProvider } from '../monitoring-providers.enum';
|
||||
import { ConsoleMonitoringService } from './console-monitoring.service';
|
||||
|
||||
const MONITORING_PROVIDER = getMonitoringProvider();
|
||||
|
||||
/**
|
||||
* @name getServerMonitoringService
|
||||
* @description Get the monitoring service based on the MONITORING_PROVIDER environment variable.
|
||||
*/
|
||||
export async function getServerMonitoringService() {
|
||||
if (!MONITORING_PROVIDER) {
|
||||
console.info(
|
||||
`No instrumentation provider specified. Returning console service...`,
|
||||
);
|
||||
|
||||
return new ConsoleMonitoringService();
|
||||
}
|
||||
|
||||
switch (MONITORING_PROVIDER) {
|
||||
case InstrumentationProvider.Baselime: {
|
||||
const { BaselimeServerMonitoringService } = await import(
|
||||
'@kit/baselime/server'
|
||||
);
|
||||
|
||||
return new BaselimeServerMonitoringService();
|
||||
}
|
||||
|
||||
case InstrumentationProvider.Sentry: {
|
||||
const { SentryServerMonitoringService } = await import(
|
||||
'@kit/sentry/server'
|
||||
);
|
||||
|
||||
return new SentryServerMonitoringService();
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new Error(
|
||||
`Please set the MONITORING_PROVIDER environment variable to register the monitoring instrumentation provider.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
packages/monitoring/src/services/monitoring.service.ts
Normal file
22
packages/monitoring/src/services/monitoring.service.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Monitoring service interface
|
||||
* @description This service is used to capture exceptions and identify users in the monitoring service
|
||||
* @example
|
||||
*/
|
||||
export abstract class MonitoringService {
|
||||
/**
|
||||
* Capture an exception
|
||||
* @param error
|
||||
* @param extra
|
||||
*/
|
||||
abstract captureException<Extra extends object>(
|
||||
error: Error & { digest?: string },
|
||||
extra?: Extra,
|
||||
): unknown;
|
||||
|
||||
/**
|
||||
* Identify a user in the monitoring service - used for tracking user actions
|
||||
* @param info
|
||||
*/
|
||||
abstract identifyUser<Info extends { id: string }>(info: Info): unknown;
|
||||
}
|
||||
Reference in New Issue
Block a user