koa.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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 {PlatformKey} from 'sentry/data/platformCategories';
  5. import {t, tct} from 'sentry/locale';
  6. import {Organization} from 'sentry/types';
  7. type StepProps = {
  8. newOrg: boolean;
  9. organization: Organization;
  10. platformKey: PlatformKey;
  11. projectId: string;
  12. sentryInitContent: string;
  13. };
  14. const performanceIntegrations: string[] = [
  15. `// Automatically instrument Node.js libraries and frameworks
  16. ...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),`,
  17. ];
  18. const performanceOtherConfig = `// Performance Monitoring
  19. tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production!`;
  20. export const steps = ({
  21. sentryInitContent,
  22. }: Partial<StepProps> = {}): LayoutProps['steps'] => [
  23. {
  24. type: StepType.INSTALL,
  25. description: t('Add the Sentry Node SDK as a dependency:'),
  26. configurations: [
  27. {
  28. language: 'bash',
  29. code: `
  30. # Using yarn
  31. yarn add @sentry/node @sentry/utils
  32. # Using npm
  33. npm install --save @sentry/node @sentry/utils
  34. `,
  35. },
  36. ],
  37. },
  38. {
  39. type: StepType.CONFIGURE,
  40. description: (
  41. <p>
  42. {tct(
  43. "Initialize Sentry as early as possible in your application's lifecycle, for example in your [code:index.ts/js] entry point:",
  44. {code: <code />}
  45. )}
  46. </p>
  47. ),
  48. configurations: [
  49. {
  50. language: 'javascript',
  51. code: `
  52. const Sentry = require("@sentry/node");
  53. const { stripUrlQueryAndFragment } = require("@sentry/utils");
  54. const Koa = require("koa");
  55. const app = new Koa();
  56. Sentry.init({
  57. ${sentryInitContent},
  58. });
  59. const requestHandler = (ctx, next) => {
  60. return new Promise((resolve, reject) => {
  61. Sentry.runWithAsyncContext(async () => {
  62. const hub = Sentry.getCurrentHub();
  63. hub.configureScope((scope) =>
  64. scope.addEventProcessor((event) =>
  65. Sentry.addRequestDataToEvent(event, ctx.request, {
  66. include: {
  67. user: false,
  68. },
  69. })
  70. )
  71. );
  72. try {
  73. await next();
  74. } catch (err) {
  75. reject(err);
  76. }
  77. resolve();
  78. });
  79. });
  80. };
  81. // this tracing middleware creates a transaction per request
  82. const tracingMiddleWare = async (ctx, next) => {
  83. const reqMethod = (ctx.method || "").toUpperCase();
  84. const reqUrl = ctx.url && stripUrlQueryAndFragment(ctx.url);
  85. // connect to trace of upstream app
  86. let traceparentData;
  87. if (ctx.request.get("sentry-trace")) {
  88. traceparentData = Sentry.extractTraceparentData(
  89. ctx.request.get("sentry-trace")
  90. );
  91. }
  92. const transaction = Sentry.startTransaction({
  93. name: \`\${reqMethod} \${reqUrl}\`,
  94. op: "http.server",
  95. ...traceparentData,
  96. });
  97. ctx.__sentry_transaction = transaction;
  98. // We put the transaction on the scope so users can attach children to it
  99. Sentry.getCurrentHub().configureScope((scope) => {
  100. scope.setSpan(transaction);
  101. });
  102. ctx.res.on("finish", () => {
  103. // Push \`transaction.finish\` to the next event loop so open spans have a chance to finish before the transaction closes
  104. setImmediate(() => {
  105. // if you're using koa router, set the matched route as transaction name
  106. if (ctx._matchedRoute) {
  107. const mountPath = ctx.mountPath || "";
  108. transaction.setName(\`\${reqMethod} \${mountPath}\${ctx._matchedRoute}\`);
  109. }
  110. transaction.setHttpStatus(ctx.status);
  111. transaction.finish();
  112. });
  113. });
  114. await next();
  115. };
  116. app.use(requestHandler);
  117. app.use(tracingMiddleWare);
  118. // usual error handler
  119. app.on("error", (err, ctx) => {
  120. Sentry.withScope((scope) => {
  121. scope.addEventProcessor((event) => {
  122. return Sentry.addRequestDataToEvent(event, ctx.request);
  123. });
  124. Sentry.captureException(err);
  125. });
  126. });
  127. app.listen(3000);
  128. `,
  129. },
  130. ],
  131. },
  132. {
  133. type: StepType.VERIFY,
  134. description: t(
  135. "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
  136. ),
  137. configurations: [
  138. {
  139. language: 'javascript',
  140. code: `
  141. app.use(async function () {
  142. throw new Error("My first Sentry error!");
  143. });
  144. `,
  145. },
  146. ],
  147. },
  148. ];
  149. export function GettingStartedWithKoa({dsn, newOrg, platformKey}: ModuleProps) {
  150. let sentryInitContent: string[] = [`dsn: "${dsn}",`];
  151. const integrations = [...performanceIntegrations];
  152. const otherConfigs = [performanceOtherConfig];
  153. if (integrations.length > 0) {
  154. sentryInitContent = sentryInitContent.concat('integrations: [', integrations, '],');
  155. }
  156. if (otherConfigs.length > 0) {
  157. sentryInitContent = sentryInitContent.concat(otherConfigs);
  158. }
  159. return (
  160. <Layout
  161. steps={steps({
  162. sentryInitContent: sentryInitContent.join('\n'),
  163. })}
  164. newOrg={newOrg}
  165. platformKey={platformKey}
  166. />
  167. );
  168. }
  169. export default GettingStartedWithKoa;