Refactor monitoring services into separate packages
Separated and isolated the responsibilities of monitoring tools. Reorganized the code by introducing a core package that contains common code related to monitoring and moved all the service operations like error capturing and identification of users into their respective packages. This ensures each tool is independent and easy to maintain.
This commit is contained in:
@@ -4,9 +4,9 @@
|
||||
"sideEffects": false,
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"clean": "git clean -xdf .turbo node_modules",
|
||||
"clean": "git clean -xdf ../.turbo node_modules",
|
||||
"format": "prettier --check \"**/*.{ts,tsx}\"",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint ..",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"prettier": "@kit/prettier-config",
|
||||
@@ -17,6 +17,7 @@
|
||||
"./components": "./src/components/index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kit/monitoring-core": "workspace:*",
|
||||
"@kit/baselime": "workspace:*",
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
@@ -13,6 +13,14 @@ const BaselimeProvider = lazy(async () => {
|
||||
};
|
||||
});
|
||||
|
||||
const SentryProvider = lazy(async () => {
|
||||
const { SentryProvider } = await import('@kit/sentry/provider');
|
||||
|
||||
return {
|
||||
default: SentryProvider,
|
||||
};
|
||||
});
|
||||
|
||||
type Config = {
|
||||
provider: InstrumentationProvider;
|
||||
providerToken: string;
|
||||
@@ -35,9 +43,8 @@ export function MonitoringProvider(
|
||||
</BaselimeProvider>
|
||||
);
|
||||
|
||||
// sentry does not require a provider
|
||||
case InstrumentationProvider.Sentry:
|
||||
return <>{props.children}</>;
|
||||
return <SentryProvider>{props.children}</SentryProvider>;
|
||||
|
||||
default:
|
||||
return <>{props.children}</>;
|
||||
12
packages/monitoring/api/src/hooks/use-monitoring.ts
Normal file
12
packages/monitoring/api/src/hooks/use-monitoring.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { MonitoringContext } from '@kit/monitoring-core';
|
||||
|
||||
/**
|
||||
* @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() {
|
||||
return useContext(MonitoringContext);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ConsoleMonitoringService } from '@kit/monitoring-core';
|
||||
|
||||
import { getMonitoringProvider } from '../get-monitoring-provider';
|
||||
import { InstrumentationProvider } from '../monitoring-providers.enum';
|
||||
import { ConsoleMonitoringService } from './console-monitoring.service';
|
||||
|
||||
const MONITORING_PROVIDER = getMonitoringProvider();
|
||||
|
||||
@@ -18,16 +18,22 @@
|
||||
"dependencies": {
|
||||
"@baselime/node-opentelemetry": "^0.5.8",
|
||||
"@baselime/react-rum": "^0.2.9",
|
||||
"@kit/monitoring-core": "workspace:*",
|
||||
"@tanstack/react-table": "^8.16.0",
|
||||
"next": "14.3.0-canary.7",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"zod": "^3.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.79",
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/tailwind-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*"
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"react": "18.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "18.2.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { useRef } from 'react';
|
||||
|
||||
import { BaselimeRum } from '@baselime/react-rum';
|
||||
|
||||
import { MonitoringContext } from '@kit/monitoring-core';
|
||||
|
||||
import { useBaselime } from '../hooks/use-baselime';
|
||||
|
||||
export function BaselimeProvider({
|
||||
children,
|
||||
apiKey,
|
||||
@@ -16,7 +22,18 @@ export function BaselimeProvider({
|
||||
enableWebVitals={enableWebVitals}
|
||||
fallback={ErrorPage ?? null}
|
||||
>
|
||||
{children}
|
||||
<MonitoringProvider>{children}</MonitoringProvider>
|
||||
</BaselimeRum>
|
||||
);
|
||||
}
|
||||
|
||||
function MonitoringProvider(props: React.PropsWithChildren) {
|
||||
const service = useBaselime();
|
||||
const provider = useRef(service);
|
||||
|
||||
return (
|
||||
<MonitoringContext.Provider value={provider.current}>
|
||||
{props.children}
|
||||
</MonitoringContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useBaselimeRum } from '@baselime/react-rum';
|
||||
|
||||
import { MonitoringService } from '../../../src/services/monitoring.service';
|
||||
import { MonitoringService } from '@kit/monitoring-core';
|
||||
|
||||
/**
|
||||
* @name useBaselime
|
||||
@@ -9,6 +11,7 @@ import { MonitoringService } from '../../../src/services/monitoring.service';
|
||||
export function useBaselime(): MonitoringService {
|
||||
const { captureException, setUser } = useBaselimeRum();
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
captureException(error: Error, extra?: React.ErrorInfo | undefined) {
|
||||
void captureException(error, extra);
|
||||
@@ -17,4 +20,5 @@ export function useBaselime(): MonitoringService {
|
||||
setUser(params.id);
|
||||
},
|
||||
} satisfies MonitoringService;
|
||||
}, [captureException, setUser]);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import process from 'node:process';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { MonitoringService } from '../../../src/services/monitoring.service';
|
||||
import { MonitoringService } from '@kit/monitoring-core';
|
||||
|
||||
const apiKey = z
|
||||
.string({
|
||||
required_error: 'API_KEY is required',
|
||||
required_error: 'BASELIME_API_KEY is required',
|
||||
})
|
||||
.parse(process.env.BASELIME_API_KEY);
|
||||
|
||||
|
||||
41
packages/monitoring/core/package.json
Normal file
41
packages/monitoring/core/package.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "@kit/monitoring-core",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"clean": "git clean -xdf .turbo node_modules",
|
||||
"format": "prettier --check \"**/*.{ts,tsx}\"",
|
||||
"lint": "eslint .",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"prettier": "@kit/prettier-config",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/tailwind-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@types/react": "^18.2.79",
|
||||
"react": "18.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"extends": [
|
||||
"@kit/eslint-config/base",
|
||||
"@kit/eslint-config/react"
|
||||
]
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MonitoringService } from './monitoring.service';
|
||||
import { MonitoringService } from '@kit/monitoring-core';
|
||||
|
||||
export class ConsoleMonitoringService implements MonitoringService {
|
||||
identifyUser() {
|
||||
3
packages/monitoring/core/src/index.ts
Normal file
3
packages/monitoring/core/src/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './monitoring.service';
|
||||
export * from './monitoring.context';
|
||||
export * from './console-monitoring.service';
|
||||
8
packages/monitoring/core/src/monitoring.context.ts
Normal file
8
packages/monitoring/core/src/monitoring.context.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { ConsoleMonitoringService } from './console-monitoring.service';
|
||||
import { MonitoringService } from './monitoring.service';
|
||||
|
||||
export const MonitoringContext = createContext<MonitoringService>(
|
||||
new ConsoleMonitoringService(),
|
||||
);
|
||||
8
packages/monitoring/core/tsconfig.json
Normal file
8
packages/monitoring/core/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@kit/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
||||
},
|
||||
"include": ["*.ts", "src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -12,13 +12,14 @@
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./server": "./src/server.ts",
|
||||
"./client": "./src/client.ts",
|
||||
"./provider": "./src/components/provider.tsx",
|
||||
"./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"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kit/monitoring-core": "workspace:*",
|
||||
"@opentelemetry/resources": "1.23.0",
|
||||
"@opentelemetry/sdk-node": "0.50.0",
|
||||
"@opentelemetry/semantic-conventions": "^1.23.0",
|
||||
@@ -30,10 +31,15 @@
|
||||
"zod": "^3.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.79",
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/tailwind-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*"
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"react": "18.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "18.2.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './hooks/use-sentry';
|
||||
19
packages/monitoring/sentry/src/components/provider.tsx
Normal file
19
packages/monitoring/sentry/src/components/provider.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useRef } from 'react';
|
||||
|
||||
import { MonitoringContext } from '@kit/monitoring-core';
|
||||
|
||||
import { SentryServerMonitoringService } from '../services/sentry-server-monitoring.service';
|
||||
|
||||
export function SentryProvider({ children }: React.PropsWithChildren) {
|
||||
return <MonitoringProvider>{children}</MonitoringProvider>;
|
||||
}
|
||||
|
||||
function MonitoringProvider(props: React.PropsWithChildren) {
|
||||
const service = useRef(new SentryServerMonitoringService());
|
||||
|
||||
return (
|
||||
<MonitoringContext.Provider value={service.current}>
|
||||
{props.children}
|
||||
</MonitoringContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { SentryServerMonitoringService } from '../services/sentry-server-monitoring.service';
|
||||
|
||||
/**
|
||||
* @name useSentry
|
||||
* @description Get the Sentry monitoring service. Sentry can be used in the browser and server - so we don't need to differentiate between the two.
|
||||
* @returns {SentryServerMonitoringService}
|
||||
*/
|
||||
export function useSentry(): SentryServerMonitoringService {
|
||||
return useMemo(() => new SentryServerMonitoringService(), []);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
import { MonitoringService } from '../../../src/services/monitoring.service';
|
||||
import { MonitoringService } from '@kit/monitoring-core';
|
||||
|
||||
/**
|
||||
* @class
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
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 serviceFactory: () => 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 (!serviceFactory) {
|
||||
throw withMonitoringService();
|
||||
}
|
||||
|
||||
return serviceFactory();
|
||||
}
|
||||
|
||||
async function withMonitoringService() {
|
||||
serviceFactory = await loadMonitoringService();
|
||||
}
|
||||
|
||||
async function loadMonitoringService(): Promise<() => MonitoringService> {
|
||||
if (!MONITORING) {
|
||||
return Promise.resolve(() => 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 as string}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
pnpm-lock.yaml
generated
65
pnpm-lock.yaml
generated
@@ -103,7 +103,7 @@ importers:
|
||||
version: link:../../packages/mailers
|
||||
'@kit/monitoring':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/monitoring
|
||||
version: link:../../packages/monitoring/api
|
||||
'@kit/next':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/next
|
||||
@@ -672,7 +672,7 @@ importers:
|
||||
version: link:../../mailers
|
||||
'@kit/monitoring':
|
||||
specifier: workspace:^
|
||||
version: link:../../monitoring
|
||||
version: link:../../monitoring/api
|
||||
'@kit/prettier-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/prettier
|
||||
@@ -791,6 +791,9 @@ importers:
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
react-dom:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
react-hook-form:
|
||||
specifier: ^7.51.3
|
||||
version: 7.51.3(react@18.2.0)
|
||||
@@ -894,7 +897,7 @@ importers:
|
||||
version: link:../../mailers
|
||||
'@kit/monitoring':
|
||||
specifier: workspace:*
|
||||
version: link:../../monitoring
|
||||
version: link:../../monitoring/api
|
||||
'@kit/prettier-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/prettier
|
||||
@@ -1042,7 +1045,7 @@ importers:
|
||||
specifier: ^3.23.0
|
||||
version: 3.23.0
|
||||
|
||||
packages/monitoring:
|
||||
packages/monitoring/api:
|
||||
dependencies:
|
||||
'@tanstack/react-table':
|
||||
specifier: ^8.16.0
|
||||
@@ -1059,22 +1062,25 @@ importers:
|
||||
devDependencies:
|
||||
'@kit/baselime':
|
||||
specifier: workspace:*
|
||||
version: link:baselime
|
||||
version: link:../baselime
|
||||
'@kit/eslint-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../tooling/eslint
|
||||
version: link:../../../tooling/eslint
|
||||
'@kit/monitoring-core':
|
||||
specifier: workspace:*
|
||||
version: link:../core
|
||||
'@kit/prettier-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../tooling/prettier
|
||||
version: link:../../../tooling/prettier
|
||||
'@kit/sentry':
|
||||
specifier: workspace:*
|
||||
version: link:sentry
|
||||
version: link:../sentry
|
||||
'@kit/tailwind-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../tooling/tailwind
|
||||
version: link:../../../tooling/tailwind
|
||||
'@kit/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:../../tooling/typescript
|
||||
version: link:../../../tooling/typescript
|
||||
'@types/react':
|
||||
specifier: ^18.2.79
|
||||
version: 18.2.79
|
||||
@@ -1090,6 +1096,9 @@ importers:
|
||||
'@baselime/react-rum':
|
||||
specifier: ^0.2.9
|
||||
version: 0.2.9(react@18.2.0)
|
||||
'@kit/monitoring-core':
|
||||
specifier: workspace:*
|
||||
version: link:../core
|
||||
'@tanstack/react-table':
|
||||
specifier: ^8.16.0
|
||||
version: 8.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
@@ -1115,9 +1124,39 @@ importers:
|
||||
'@kit/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/typescript
|
||||
'@types/react':
|
||||
specifier: ^18.2.79
|
||||
version: 18.2.79
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
|
||||
packages/monitoring/core:
|
||||
devDependencies:
|
||||
'@kit/eslint-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/eslint
|
||||
'@kit/prettier-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/prettier
|
||||
'@kit/tailwind-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/tailwind
|
||||
'@kit/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/typescript
|
||||
'@types/react':
|
||||
specifier: ^18.2.79
|
||||
version: 18.2.79
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
|
||||
packages/monitoring/sentry:
|
||||
dependencies:
|
||||
'@kit/monitoring-core':
|
||||
specifier: workspace:*
|
||||
version: link:../core
|
||||
'@opentelemetry/resources':
|
||||
specifier: 1.23.0
|
||||
version: 1.23.0(@opentelemetry/api@1.8.0)
|
||||
@@ -1158,6 +1197,12 @@ importers:
|
||||
'@kit/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:../../../tooling/typescript
|
||||
'@types/react':
|
||||
specifier: ^18.2.79
|
||||
version: 18.2.79
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
|
||||
packages/next:
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user