koa.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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 {getUploadSourceMapsStep} from 'sentry/components/onboarding/gettingStartedDoc/utils';
  5. import {PlatformKey} from 'sentry/data/platformCategories';
  6. import {t, tct} from 'sentry/locale';
  7. import {Organization} from 'sentry/types';
  8. type StepProps = {
  9. newOrg: boolean;
  10. organization: Organization;
  11. platformKey: PlatformKey;
  12. projectId: string;
  13. sentryInitContent: string;
  14. };
  15. const performanceIntegrations: string[] = [
  16. `// Automatically instrument Node.js libraries and frameworks
  17. ...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),`,
  18. ];
  19. const performanceOtherConfig = `// Performance Monitoring
  20. tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production!`;
  21. export const steps = ({
  22. sentryInitContent,
  23. ...props
  24. }: Partial<StepProps> = {}): LayoutProps['steps'] => [
  25. {
  26. type: StepType.INSTALL,
  27. description: t('Add the Sentry Node SDK as a dependency:'),
  28. configurations: [
  29. {
  30. language: 'bash',
  31. code: `
  32. # Using yarn
  33. yarn add @sentry/node @sentry/utils
  34. # Using npm
  35. npm install --save @sentry/node @sentry/utils
  36. `,
  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. const Sentry = require("@sentry/node");
  55. const { stripUrlQueryAndFragment } = require("@sentry/utils");
  56. const Koa = require("koa");
  57. const app = new Koa();
  58. Sentry.init({
  59. ${sentryInitContent},
  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. // usual error handler
  121. app.on("error", (err, ctx) => {
  122. Sentry.withScope((scope) => {
  123. scope.addEventProcessor((event) => {
  124. return Sentry.addRequestDataToEvent(event, ctx.request);
  125. });
  126. Sentry.captureException(err);
  127. });
  128. });
  129. app.listen(3000);
  130. `,
  131. },
  132. ],
  133. },
  134. getUploadSourceMapsStep({
  135. guideLink: 'https://docs.sentry.io/platforms/node/guides/koa/sourcemaps/',
  136. ...props,
  137. }),
  138. {
  139. type: StepType.VERIFY,
  140. description: t(
  141. "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
  142. ),
  143. configurations: [
  144. {
  145. language: 'javascript',
  146. code: `
  147. app.use(async function () {
  148. throw new Error("My first Sentry error!");
  149. });
  150. `,
  151. },
  152. ],
  153. },
  154. ];
  155. export function GettingStartedWithKoa({
  156. dsn,
  157. organization,
  158. newOrg,
  159. platformKey,
  160. projectId,
  161. }: ModuleProps) {
  162. let sentryInitContent: string[] = [`dsn: "${dsn}",`];
  163. const integrations = [...performanceIntegrations];
  164. const otherConfigs = [performanceOtherConfig];
  165. if (integrations.length > 0) {
  166. sentryInitContent = sentryInitContent.concat('integrations: [', integrations, '],');
  167. }
  168. if (otherConfigs.length > 0) {
  169. sentryInitContent = sentryInitContent.concat(otherConfigs);
  170. }
  171. return (
  172. <Layout
  173. steps={steps({
  174. sentryInitContent: sentryInitContent.join('\n'),
  175. organization,
  176. newOrg,
  177. platformKey,
  178. projectId,
  179. })}
  180. newOrg={newOrg}
  181. platformKey={platformKey}
  182. />
  183. );
  184. }
  185. export default GettingStartedWithKoa;