koa.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
  2. import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
  3. import {StepProps, StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  4. import {getUploadSourceMapsStep} from 'sentry/components/onboarding/gettingStartedDoc/utils';
  5. import {t, tct} from 'sentry/locale';
  6. import {
  7. getDefaultInitParams,
  8. getDefaultNodeImports,
  9. getInstallSnippet,
  10. getProductInitParams,
  11. getProductIntegrations,
  12. getProductSelectionMap,
  13. joinWithIndentation,
  14. } from 'sentry/utils/gettingStartedDocs/node';
  15. interface StepsParams {
  16. hasPerformanceMonitoring: boolean;
  17. importContent: string;
  18. initContent: string;
  19. installSnippet: string;
  20. sourceMapStep: StepProps;
  21. }
  22. const performanceIntegrations: string[] = [
  23. '// Automatically instrument Node.js libraries and frameworks',
  24. '...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),',
  25. ];
  26. export const steps = ({
  27. installSnippet,
  28. importContent,
  29. initContent,
  30. hasPerformanceMonitoring,
  31. sourceMapStep,
  32. }: StepsParams): LayoutProps['steps'] => [
  33. {
  34. type: StepType.INSTALL,
  35. description: t('Add the Sentry Node SDK as a dependency:'),
  36. configurations: [
  37. {
  38. language: 'bash',
  39. code: installSnippet,
  40. },
  41. ],
  42. },
  43. {
  44. type: StepType.CONFIGURE,
  45. description: (
  46. <p>
  47. {tct(
  48. "Initialize Sentry as early as possible in your application's lifecycle, for example in your [code:index.ts/js] entry point:",
  49. {code: <code />}
  50. )}
  51. </p>
  52. ),
  53. configurations: [
  54. {
  55. language: 'javascript',
  56. code: `
  57. ${importContent}
  58. const app = new Koa();
  59. Sentry.init({
  60. ${initContent}
  61. });${
  62. hasPerformanceMonitoring
  63. ? `
  64. const requestHandler = (ctx, next) => {
  65. return new Promise((resolve, reject) => {
  66. Sentry.runWithAsyncContext(async () => {
  67. const hub = Sentry.getCurrentHub();
  68. hub.configureScope((scope) =>
  69. scope.addEventProcessor((event) =>
  70. Sentry.addRequestDataToEvent(event, ctx.request, {
  71. include: {
  72. user: false,
  73. },
  74. })
  75. )
  76. );
  77. try {
  78. await next();
  79. } catch (err) {
  80. reject(err);
  81. }
  82. resolve();
  83. });
  84. });
  85. };
  86. // This tracing middleware creates a transaction per request
  87. const tracingMiddleWare = async (ctx, next) => {
  88. const reqMethod = (ctx.method || "").toUpperCase();
  89. const reqUrl = ctx.url && stripUrlQueryAndFragment(ctx.url);
  90. // Connect to trace of upstream app
  91. let traceparentData;
  92. if (ctx.request.get("sentry-trace")) {
  93. traceparentData = Sentry.extractTraceparentData(
  94. ctx.request.get("sentry-trace")
  95. );
  96. }
  97. const transaction = Sentry.startTransaction({
  98. name: \`\${reqMethod} \${reqUrl}\`,
  99. op: "http.server",
  100. ...traceparentData,
  101. });
  102. ctx.__sentry_transaction = transaction;
  103. // We put the transaction on the scope so users can attach children to it
  104. Sentry.getCurrentHub().configureScope((scope) => {
  105. scope.setSpan(transaction);
  106. });
  107. ctx.res.on("finish", () => {
  108. // Push \`transaction.finish\` to the next event loop so open spans have a chance to finish before the transaction closes
  109. setImmediate(() => {
  110. // If you're using koa router, set the matched route as transaction name
  111. if (ctx._matchedRoute) {
  112. const mountPath = ctx.mountPath || "";
  113. transaction.setName(\`\${reqMethod} \${mountPath}\${ctx._matchedRoute}\`);
  114. }
  115. transaction.setHttpStatus(ctx.status);
  116. transaction.finish();
  117. });
  118. });
  119. await next();
  120. };
  121. app.use(requestHandler);
  122. app.use(tracingMiddleWare);`
  123. : ''
  124. }
  125. // Send errors to Sentry
  126. app.on("error", (err, ctx) => {
  127. Sentry.withScope((scope) => {
  128. scope.addEventProcessor((event) => {
  129. return Sentry.addRequestDataToEvent(event, ctx.request);
  130. });
  131. Sentry.captureException(err);
  132. });
  133. });
  134. app.listen(3000);
  135. `,
  136. },
  137. ],
  138. },
  139. sourceMapStep,
  140. {
  141. type: StepType.VERIFY,
  142. description: t(
  143. "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
  144. ),
  145. configurations: [
  146. {
  147. language: 'javascript',
  148. code: `
  149. app.use(async function () {
  150. throw new Error("My first Sentry error!");
  151. });
  152. `,
  153. },
  154. ],
  155. },
  156. ];
  157. export function GettingStartedWithKoa({
  158. dsn,
  159. newOrg,
  160. platformKey,
  161. activeProductSelection = [],
  162. organization,
  163. projectId,
  164. ...props
  165. }: ModuleProps) {
  166. const productSelection = getProductSelectionMap(activeProductSelection);
  167. const additionalPackages = productSelection['performance-monitoring']
  168. ? ['@sentry/utils']
  169. : [];
  170. const installSnippet = getInstallSnippet({productSelection, additionalPackages});
  171. let imports = getDefaultNodeImports({productSelection});
  172. imports = imports.concat([
  173. 'import { stripUrlQueryAndFragment } from "@sentry/utils";',
  174. 'import Koa from "koa";',
  175. ]);
  176. const integrations = [
  177. ...(productSelection['performance-monitoring'] ? performanceIntegrations : []),
  178. ...getProductIntegrations({productSelection}),
  179. ];
  180. const integrationParam =
  181. integrations.length > 0
  182. ? `integrations: [\n${joinWithIndentation(integrations)}\n],`
  183. : null;
  184. const initContent = joinWithIndentation([
  185. ...getDefaultInitParams({dsn}),
  186. ...(integrationParam ? [integrationParam] : []),
  187. ...getProductInitParams({productSelection}),
  188. ]);
  189. return (
  190. <Layout
  191. steps={steps({
  192. installSnippet,
  193. importContent: imports.join('\n'),
  194. initContent,
  195. hasPerformanceMonitoring: productSelection['performance-monitoring'],
  196. sourceMapStep: getUploadSourceMapsStep({
  197. guideLink: 'https://docs.sentry.io/platforms/node/guides/koa/sourcemaps/',
  198. organization,
  199. platformKey,
  200. projectId,
  201. newOrg,
  202. }),
  203. })}
  204. newOrg={newOrg}
  205. platformKey={platformKey}
  206. {...props}
  207. />
  208. );
  209. }
  210. export default GettingStartedWithKoa;