Merge branch 'main' of github.com:makerkit/next-supabase-saas-kit-turbo

This commit is contained in:
giancarlo
2024-05-28 15:18:24 +07:00
16 changed files with 155 additions and 97 deletions

View File

@@ -13,4 +13,4 @@ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
# MONITORING
NEXT_PUBLIC_MONITORING_PROVIDER=
MONITORING_INSTRUMENTATION_ENABLED=false
ENABLE_MONITORING_INSTRUMENTATION=false

View File

@@ -2,18 +2,12 @@
* This file is used to register monitoring instrumentation
* for your Next.js application.
*/
export async function register() {
// only run in nodejs runtime
if (
process.env.NEXT_RUNTIME === 'nodejs' &&
process.env.MONITORING_INSTRUMENTATION_ENABLED === 'true'
) {
const { registerMonitoringInstrumentation } = await import(
'@kit/monitoring/instrumentation'
);
const { registerMonitoringInstrumentation } = await import(
'@kit/monitoring/instrumentation'
);
// Register monitoring instrumentation based on the MONITORING_PROVIDER environment variable.
return registerMonitoringInstrumentation();
}
// Register monitoring instrumentation
// based on the MONITORING_PROVIDER environment variable.
await registerMonitoringInstrumentation();
}

View File

@@ -4,7 +4,7 @@ Please set the following environment variable to your preferred monitoring provi
```
NEXT_PUBLIC_MONITORING_PROVIDER=
MONITORING_INSTRUMENTATION_ENABLED=true
ENABLE_MONITORING_INSTRUMENTATION=true
```
## Available Providers
@@ -32,8 +32,8 @@ NEXT_PUBLIC_MONITORING_PROVIDER=sentry
## Instrumentation
To enable instrumentation, set the `MONITORING_INSTRUMENTATION_ENABLED` environment variable to `true`.
To enable instrumentation, set the `ENABLE_MONITORING_INSTRUMENTATION` environment variable to `true`.
```
MONITORING_INSTRUMENTATION_ENABLED=true
ENABLE_MONITORING_INSTRUMENTATION=true
```

View File

@@ -28,11 +28,9 @@ export async function getServerMonitoringService() {
}
case InstrumentationProvider.Sentry: {
const { SentryServerMonitoringService } = await import(
'@kit/sentry/server'
);
const { SentryMonitoringService } = await import('@kit/sentry');
return new SentryServerMonitoringService();
return new SentryMonitoringService();
}
default: {

View File

@@ -5,6 +5,10 @@
* Please set the MONITORING_PROVIDER environment variable to 'baselime' to register Baselime instrumentation.
*/
export async function registerInstrumentation() {
if (!process.env.ENABLE_MONITORING_INSTRUMENTATION) {
return;
}
const serviceName = process.env.INSTRUMENTATION_SERVICE_NAME;
if (!serviceName) {
@@ -14,19 +18,20 @@ export async function registerInstrumentation() {
`);
}
const { BaselimeSDK, BetterHttpInstrumentation, VercelPlugin } = await import(
'@baselime/node-opentelemetry'
);
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { BaselimeSDK, BetterHttpInstrumentation, VercelPlugin } =
await import('@baselime/node-opentelemetry');
const sdk = new BaselimeSDK({
serverless: true,
service: serviceName,
instrumentations: [
new BetterHttpInstrumentation({
plugins: [new VercelPlugin()],
}),
],
});
const sdk = new BaselimeSDK({
serverless: true,
service: serviceName,
instrumentations: [
new BetterHttpInstrumentation({
plugins: [new VercelPlugin()],
}),
],
});
sdk.start();
sdk.start();
}
}

View File

@@ -11,12 +11,10 @@
"prettier": "@kit/prettier-config",
"exports": {
".": "./src/index.ts",
"./server": "./src/server.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.edge.config.ts"
"./config/client": "./src/sentry.client.config.ts",
"./config/server": "./src/sentry.client.server.ts"
},
"dependencies": {
"@opentelemetry/exporter-jaeger": "1.24.1",

View File

@@ -2,14 +2,14 @@ import { useRef } from 'react';
import { MonitoringContext } from '@kit/monitoring-core';
import { SentryServerMonitoringService } from '../services/sentry-server-monitoring.service';
import { SentryMonitoringService } from '../services/sentry-monitoring.service';
export function SentryProvider({ children }: React.PropsWithChildren) {
return <MonitoringProvider>{children}</MonitoringProvider>;
}
function MonitoringProvider(props: React.PropsWithChildren) {
const service = useRef(new SentryServerMonitoringService());
const service = useRef(new SentryMonitoringService());
return (
<MonitoringContext.Provider value={service.current}>

View File

@@ -1,23 +0,0 @@
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// Replay may only be enabled for the client-side
integrations: [Sentry.replayIntegration()],
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
// Capture Replay for 10% of all sessions,
// plus for 100% of sessions with an error
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
});

View File

@@ -1,6 +0,0 @@
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
});

View File

@@ -1,6 +0,0 @@
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
});

View File

@@ -0,0 +1 @@
export * from './services/sentry-monitoring.service';

View File

@@ -5,32 +5,46 @@
* Please set the MONITORING_PROVIDER environment variable to 'sentry' to register Sentry instrumentation.
*/
export async function registerInstrumentation() {
const serviceName = process.env.INSTRUMENTATION_SERVICE_NAME;
const { initializeSentryServerClient } = await import(
'./sentry.server.config'
);
if (!serviceName) {
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.`,
);
// initialize the Sentry client in the server
void initializeSentryServerClient();
if (!process.env.ENABLE_MONITORING_INSTRUMENTATION) {
return;
}
const { Resource } = await import('@opentelemetry/resources');
const { NodeSDK } = await import('@opentelemetry/sdk-node');
// make sure the instrumentation is only run in a Node.js environment
if (process.env.NEXT_RUNTIME === 'nodejs') {
const serviceName = process.env.INSTRUMENTATION_SERVICE_NAME;
const { SEMRESATTRS_SERVICE_NAME } = await import(
'@opentelemetry/semantic-conventions'
);
if (!serviceName) {
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.`,
);
}
const { SentrySpanProcessor, SentryPropagator } = await import(
'@sentry/opentelemetry-node'
);
const { Resource } = await import('@opentelemetry/resources');
const { NodeSDK } = await import('@opentelemetry/sdk-node');
const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: serviceName,
}),
spanProcessors: [new SentrySpanProcessor()],
textMapPropagator: new SentryPropagator(),
});
const { SEMRESATTRS_SERVICE_NAME } = await import(
'@opentelemetry/semantic-conventions'
);
sdk.start();
const { SentrySpanProcessor, SentryPropagator } = await import(
'@sentry/opentelemetry-node'
);
const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: serviceName,
}),
spanProcessors: [new SentrySpanProcessor()],
textMapPropagator: new SentryPropagator(),
});
sdk.start();
}
}

View File

@@ -0,0 +1,39 @@
import * as Sentry from '@sentry/nextjs';
type Parameters<T extends (args: never) => unknown> = T extends (
...args: infer P
) => unknown
? P
: never;
/**
* @name initializeSentryBrowserClient
* @description Initialize the Sentry client
* @param props
*/
export function initializeSentryBrowserClient(
props: Parameters<typeof Sentry.init>[0] = {},
) {
return Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// Replay may only be enabled for the client-side
integrations: [Sentry.replayIntegration()],
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: props?.tracesSampleRate ?? 1.0,
// Capture Replay for 10% of all sessions,
// plus for 100% of sessions with an error
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps,
...props,
});
}

View File

@@ -0,0 +1,27 @@
import * as Sentry from '@sentry/nextjs';
type Parameters<T extends (args: never) => unknown> = T extends (
...args: infer P
) => unknown
? P
: never;
/**
* @name initializeSentryServerClient
* @description Initialize the Sentry client in the server
* @param props
*/
export function initializeSentryServerClient(
props: Parameters<typeof Sentry.init>[0] = {},
) {
return Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps,
...props,
});
}

View File

@@ -1 +0,0 @@
export * from './services/sentry-server-monitoring.service';

View File

@@ -7,7 +7,11 @@ import { MonitoringService } from '@kit/monitoring-core';
* @implements {MonitoringService}
* ServerSentryMonitoringService is responsible for capturing exceptions and identifying users using the Sentry monitoring service.
*/
export class SentryServerMonitoringService implements MonitoringService {
export class SentryMonitoringService implements MonitoringService {
constructor() {
void this.initialize();
}
captureException(error: Error | null) {
return Sentry.captureException(error);
}
@@ -22,4 +26,18 @@ export class SentryServerMonitoringService implements MonitoringService {
identifyUser(user: Sentry.User) {
Sentry.setUser(user);
}
private initialize() {
return this.initializeIfBrowser();
}
private async initializeIfBrowser() {
if (typeof document !== 'undefined') {
const { initializeSentryBrowserClient } = await import(
'../sentry.client.config'
);
initializeSentryBrowserClient();
}
}
}