Files
2024-02-15 17:01:50 +00:00

206 lines
5.5 KiB
TypeScript

import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
import type {
Docs,
DocsParams,
OnboardingConfig,
} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {getUploadSourceMapsStep} from 'sentry/components/onboarding/gettingStartedDoc/utils';
import {getJSServerMetricsOnboarding} from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsOnboarding';
import {ProductSolution} from 'sentry/components/onboarding/productSelection';
import {t, tct} from 'sentry/locale';
import type {ProductSelectionMap} from 'sentry/utils/gettingStartedDocs/node';
import {
getDefaultNodeImports,
getInstallConfig,
} from 'sentry/utils/gettingStartedDocs/node';
type Params = DocsParams;
const productSelection = (params: Params): ProductSelectionMap => {
return {
[ProductSolution.ERROR_MONITORING]: true,
[ProductSolution.PROFILING]: params.isProfilingSelected,
[ProductSolution.PERFORMANCE_MONITORING]: params.isPerformanceSelected,
[ProductSolution.SESSION_REPLAY]: params.isReplaySelected,
};
};
const getSdkSetupSnippet = (params: Params) => `
${getDefaultNodeImports({productSelection: productSelection(params)}).join('\n')}
import { stripUrlQueryAndFragment } from "@sentry/utils";
import Koa from "koa";
const app = new Koa();
Sentry.init({
dsn: "${params.dsn}",
integrations: [${
params.isPerformanceSelected
? `
// Automatically instrument Node.js libraries and frameworks
...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),`
: ''
}${
params.isProfilingSelected
? `
new ProfilingIntegration(),`
: ''
}
],${
params.isPerformanceSelected
? `
// Performance Monitoring
tracesSampleRate: 1.0, // Capture 100% of the transactions`
: ''
}${
params.isProfilingSelected
? `
// Set sampling rate for profiling - this is relative to tracesSampleRate
profilesSampleRate: 1.0,`
: ''
}
});${
params.isPerformanceSelected
? `
const requestHandler = (ctx, next) => {
return new Promise((resolve, reject) => {
Sentry.runWithAsyncContext(async () => {
const hub = Sentry.getCurrentHub();
hub.configureScope((scope) =>
scope.addEventProcessor((event) =>
Sentry.addRequestDataToEvent(event, ctx.request, {
include: {
user: false,
},
})
)
);
try {
await next();
} catch (err) {
reject(err);
}
resolve();
});
});
};
// This tracing middleware creates a transaction per request
const tracingMiddleWare = async (ctx, next) => {
const reqMethod = (ctx.method || "").toUpperCase();
const reqUrl = ctx.url && stripUrlQueryAndFragment(ctx.url);
// Connect to trace of upstream app
let traceparentData;
if (ctx.request.get("sentry-trace")) {
traceparentData = Sentry.extractTraceparentData(
ctx.request.get("sentry-trace")
);
}
const transaction = Sentry.startTransaction({
name: \`\${reqMethod} \${reqUrl}\`,
op: "http.server",
...traceparentData,
});
ctx.__sentry_transaction = transaction;
// We put the transaction on the scope so users can attach children to it
Sentry.getCurrentHub().configureScope((scope) => {
scope.setSpan(transaction);
});
ctx.res.on("finish", () => {
// Push \`transaction.finish\` to the next event loop so open spans have a chance to finish before the transaction closes
setImmediate(() => {
// If you're using koa router, set the matched route as transaction name
if (ctx._matchedRoute) {
const mountPath = ctx.mountPath || "";
transaction.setName(\`\${reqMethod} \${mountPath}\${ctx._matchedRoute}\`);
}
transaction.setHttpStatus(ctx.status);
transaction.finish();
});
});
await next();
};
app.use(requestHandler);
app.use(tracingMiddleWare);`
: ''
}
// Send errors to Sentry
app.on("error", (err, ctx) => {
Sentry.withScope((scope) => {
scope.addEventProcessor((event) => {
return Sentry.addRequestDataToEvent(event, ctx.request);
});
Sentry.captureException(err);
});
});
app.listen(3000);`;
const getVerifySnippet = () => `
app.use(async function () {
throw new Error("My first Sentry error!");
});
`;
const onboarding: OnboardingConfig = {
install: params => [
{
type: StepType.INSTALL,
description: t('Add the Sentry Node SDK as a dependency:'),
configurations: getInstallConfig(params, {
additionalPackages: params.isPerformanceSelected ? ['@sentry/utils'] : [],
}),
},
],
configure: params => [
{
type: StepType.CONFIGURE,
description: tct(
"Initialize Sentry as early as possible in your application's lifecycle, for example in your [code:index.ts/js] entry point:",
{code: <code />}
),
configurations: [
{
language: 'javascript',
code: getSdkSetupSnippet(params),
},
],
},
getUploadSourceMapsStep({
guideLink: 'https://docs.sentry.io/platforms/node/guides/koa/sourcemaps/',
...params,
}),
],
verify: () => [
{
type: StepType.VERIFY,
description: t(
"This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
),
configurations: [
{
language: 'javascript',
code: getVerifySnippet(),
},
],
},
],
};
const docs: Docs = {
onboarding,
customMetricsOnboarding: getJSServerMetricsOnboarding(),
};
export default docs;