koa.tsx 5.6 KB

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