Merge branch 'main' of github.com:makerkit/next-supabase-saas-kit-turbo
This commit is contained in:
@@ -13,4 +13,4 @@ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
|
|||||||
|
|
||||||
# MONITORING
|
# MONITORING
|
||||||
NEXT_PUBLIC_MONITORING_PROVIDER=
|
NEXT_PUBLIC_MONITORING_PROVIDER=
|
||||||
MONITORING_INSTRUMENTATION_ENABLED=false
|
ENABLE_MONITORING_INSTRUMENTATION=false
|
||||||
|
|||||||
@@ -2,18 +2,12 @@
|
|||||||
* This file is used to register monitoring instrumentation
|
* This file is used to register monitoring instrumentation
|
||||||
* for your Next.js application.
|
* for your Next.js application.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export async function register() {
|
export async function register() {
|
||||||
// only run in nodejs runtime
|
const { registerMonitoringInstrumentation } = await import(
|
||||||
if (
|
'@kit/monitoring/instrumentation'
|
||||||
process.env.NEXT_RUNTIME === 'nodejs' &&
|
);
|
||||||
process.env.MONITORING_INSTRUMENTATION_ENABLED === 'true'
|
|
||||||
) {
|
|
||||||
const { registerMonitoringInstrumentation } = await import(
|
|
||||||
'@kit/monitoring/instrumentation'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Register monitoring instrumentation based on the MONITORING_PROVIDER environment variable.
|
// Register monitoring instrumentation
|
||||||
return registerMonitoringInstrumentation();
|
// based on the MONITORING_PROVIDER environment variable.
|
||||||
}
|
await registerMonitoringInstrumentation();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Please set the following environment variable to your preferred monitoring provi
|
|||||||
|
|
||||||
```
|
```
|
||||||
NEXT_PUBLIC_MONITORING_PROVIDER=
|
NEXT_PUBLIC_MONITORING_PROVIDER=
|
||||||
MONITORING_INSTRUMENTATION_ENABLED=true
|
ENABLE_MONITORING_INSTRUMENTATION=true
|
||||||
```
|
```
|
||||||
|
|
||||||
## Available Providers
|
## Available Providers
|
||||||
@@ -32,8 +32,8 @@ NEXT_PUBLIC_MONITORING_PROVIDER=sentry
|
|||||||
|
|
||||||
## Instrumentation
|
## 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
|
||||||
```
|
```
|
||||||
@@ -28,11 +28,9 @@ export async function getServerMonitoringService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case InstrumentationProvider.Sentry: {
|
case InstrumentationProvider.Sentry: {
|
||||||
const { SentryServerMonitoringService } = await import(
|
const { SentryMonitoringService } = await import('@kit/sentry');
|
||||||
'@kit/sentry/server'
|
|
||||||
);
|
|
||||||
|
|
||||||
return new SentryServerMonitoringService();
|
return new SentryMonitoringService();
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
* Please set the MONITORING_PROVIDER environment variable to 'baselime' to register Baselime instrumentation.
|
* Please set the MONITORING_PROVIDER environment variable to 'baselime' to register Baselime instrumentation.
|
||||||
*/
|
*/
|
||||||
export async function registerInstrumentation() {
|
export async function registerInstrumentation() {
|
||||||
|
if (!process.env.ENABLE_MONITORING_INSTRUMENTATION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const serviceName = process.env.INSTRUMENTATION_SERVICE_NAME;
|
const serviceName = process.env.INSTRUMENTATION_SERVICE_NAME;
|
||||||
|
|
||||||
if (!serviceName) {
|
if (!serviceName) {
|
||||||
@@ -14,19 +18,20 @@ export async function registerInstrumentation() {
|
|||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { BaselimeSDK, BetterHttpInstrumentation, VercelPlugin } = await import(
|
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
||||||
'@baselime/node-opentelemetry'
|
const { BaselimeSDK, BetterHttpInstrumentation, VercelPlugin } =
|
||||||
);
|
await import('@baselime/node-opentelemetry');
|
||||||
|
|
||||||
const sdk = new BaselimeSDK({
|
const sdk = new BaselimeSDK({
|
||||||
serverless: true,
|
serverless: true,
|
||||||
service: serviceName,
|
service: serviceName,
|
||||||
instrumentations: [
|
instrumentations: [
|
||||||
new BetterHttpInstrumentation({
|
new BetterHttpInstrumentation({
|
||||||
plugins: [new VercelPlugin()],
|
plugins: [new VercelPlugin()],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
sdk.start();
|
sdk.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,10 @@
|
|||||||
"prettier": "@kit/prettier-config",
|
"prettier": "@kit/prettier-config",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./server": "./src/server.ts",
|
|
||||||
"./provider": "./src/components/provider.tsx",
|
"./provider": "./src/components/provider.tsx",
|
||||||
"./instrumentation": "./src/instrumentation.ts",
|
"./instrumentation": "./src/instrumentation.ts",
|
||||||
"./config/client": "./src/config/sentry.client.config.ts",
|
"./config/client": "./src/sentry.client.config.ts",
|
||||||
"./config/server": "./src/config/sentry.server.config.ts",
|
"./config/server": "./src/sentry.client.server.ts"
|
||||||
"./config/edge": "./src/config/sentry.edge.config.ts"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opentelemetry/exporter-jaeger": "1.24.1",
|
"@opentelemetry/exporter-jaeger": "1.24.1",
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import { useRef } from 'react';
|
|||||||
|
|
||||||
import { MonitoringContext } from '@kit/monitoring-core';
|
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) {
|
export function SentryProvider({ children }: React.PropsWithChildren) {
|
||||||
return <MonitoringProvider>{children}</MonitoringProvider>;
|
return <MonitoringProvider>{children}</MonitoringProvider>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function MonitoringProvider(props: React.PropsWithChildren) {
|
function MonitoringProvider(props: React.PropsWithChildren) {
|
||||||
const service = useRef(new SentryServerMonitoringService());
|
const service = useRef(new SentryMonitoringService());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MonitoringContext.Provider value={service.current}>
|
<MonitoringContext.Provider value={service.current}>
|
||||||
|
|||||||
@@ -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
|
|
||||||
});
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import * as Sentry from '@sentry/nextjs';
|
|
||||||
|
|
||||||
Sentry.init({
|
|
||||||
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
||||||
tracesSampleRate: 1.0,
|
|
||||||
});
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import * as Sentry from '@sentry/nextjs';
|
|
||||||
|
|
||||||
Sentry.init({
|
|
||||||
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
||||||
tracesSampleRate: 1.0,
|
|
||||||
});
|
|
||||||
1
packages/monitoring/sentry/src/index.ts
Normal file
1
packages/monitoring/sentry/src/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './services/sentry-monitoring.service';
|
||||||
@@ -5,32 +5,46 @@
|
|||||||
* Please set the MONITORING_PROVIDER environment variable to 'sentry' to register Sentry instrumentation.
|
* Please set the MONITORING_PROVIDER environment variable to 'sentry' to register Sentry instrumentation.
|
||||||
*/
|
*/
|
||||||
export async function registerInstrumentation() {
|
export async function registerInstrumentation() {
|
||||||
const serviceName = process.env.INSTRUMENTATION_SERVICE_NAME;
|
const { initializeSentryServerClient } = await import(
|
||||||
|
'./sentry.server.config'
|
||||||
|
);
|
||||||
|
|
||||||
if (!serviceName) {
|
// initialize the Sentry client in the server
|
||||||
throw new Error(
|
void initializeSentryServerClient();
|
||||||
`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.`,
|
|
||||||
);
|
if (!process.env.ENABLE_MONITORING_INSTRUMENTATION) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { Resource } = await import('@opentelemetry/resources');
|
// make sure the instrumentation is only run in a Node.js environment
|
||||||
const { NodeSDK } = await import('@opentelemetry/sdk-node');
|
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
||||||
|
const serviceName = process.env.INSTRUMENTATION_SERVICE_NAME;
|
||||||
|
|
||||||
const { SEMRESATTRS_SERVICE_NAME } = await import(
|
if (!serviceName) {
|
||||||
'@opentelemetry/semantic-conventions'
|
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(
|
const { Resource } = await import('@opentelemetry/resources');
|
||||||
'@sentry/opentelemetry-node'
|
const { NodeSDK } = await import('@opentelemetry/sdk-node');
|
||||||
);
|
|
||||||
|
|
||||||
const sdk = new NodeSDK({
|
const { SEMRESATTRS_SERVICE_NAME } = await import(
|
||||||
resource: new Resource({
|
'@opentelemetry/semantic-conventions'
|
||||||
[SEMRESATTRS_SERVICE_NAME]: serviceName,
|
);
|
||||||
}),
|
|
||||||
spanProcessors: [new SentrySpanProcessor()],
|
|
||||||
textMapPropagator: new SentryPropagator(),
|
|
||||||
});
|
|
||||||
|
|
||||||
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
packages/monitoring/sentry/src/sentry.client.config.ts
Normal file
39
packages/monitoring/sentry/src/sentry.client.config.ts
Normal 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,
|
||||||
|
});
|
||||||
|
}
|
||||||
27
packages/monitoring/sentry/src/sentry.server.config.ts
Normal file
27
packages/monitoring/sentry/src/sentry.server.config.ts
Normal 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,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './services/sentry-server-monitoring.service';
|
|
||||||
@@ -7,7 +7,11 @@ import { MonitoringService } from '@kit/monitoring-core';
|
|||||||
* @implements {MonitoringService}
|
* @implements {MonitoringService}
|
||||||
* ServerSentryMonitoringService is responsible for capturing exceptions and identifying users using the Sentry monitoring service.
|
* 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) {
|
captureException(error: Error | null) {
|
||||||
return Sentry.captureException(error);
|
return Sentry.captureException(error);
|
||||||
}
|
}
|
||||||
@@ -22,4 +26,18 @@ export class SentryServerMonitoringService implements MonitoringService {
|
|||||||
identifyUser(user: Sentry.User) {
|
identifyUser(user: Sentry.User) {
|
||||||
Sentry.setUser(user);
|
Sentry.setUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private initialize() {
|
||||||
|
return this.initializeIfBrowser();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async initializeIfBrowser() {
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
const { initializeSentryBrowserClient } = await import(
|
||||||
|
'../sentry.client.config'
|
||||||
|
);
|
||||||
|
|
||||||
|
initializeSentryBrowserClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user