nestjs.tsx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import ExternalLink from 'sentry/components/links/externalLink';
  2. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  3. import type {
  4. Docs,
  5. DocsParams,
  6. OnboardingConfig,
  7. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  8. import {getUploadSourceMapsStep} from 'sentry/components/onboarding/gettingStartedDoc/utils';
  9. import {
  10. getCrashReportApiIntroduction,
  11. getCrashReportInstallDescription,
  12. getCrashReportJavaScriptInstallStep,
  13. getCrashReportModalConfigDescription,
  14. getCrashReportModalIntroduction,
  15. } from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding';
  16. import {getJSServerMetricsOnboarding} from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsOnboarding';
  17. import {t, tct} from 'sentry/locale';
  18. import {
  19. getImportInstrumentSnippet,
  20. getInstallConfig,
  21. getSdkInitSnippet,
  22. } from 'sentry/utils/gettingStartedDocs/node';
  23. type Params = DocsParams;
  24. const getSdkSetupSnippet = () => `
  25. ${getImportInstrumentSnippet('esm')}
  26. // All other imports below
  27. import { NestFactory } from '@nestjs/core';
  28. import { AppModule } from './app.module';
  29. async function bootstrap() {
  30. const app = await NestFactory.create(AppModule);
  31. await app.listen(3000);
  32. }
  33. bootstrap();
  34. `;
  35. const getAppModuleSnippet = () => `
  36. import { Module } from '@nestjs/common';
  37. import { SentryModule } from '@sentry/nestjs/setup';
  38. import { AppController } from './app.controller';
  39. import { AppService } from './app.service';
  40. @Module({
  41. imports: [
  42. SentryModule.forRoot(),
  43. // ...other modules
  44. ],
  45. controllers: [AppController],
  46. providers: [AppService],
  47. })
  48. export class AppModule {}
  49. `;
  50. const getVerifySnippet = () => `
  51. @Get("/debug-sentry")
  52. getError() {
  53. throw new Error("My first Sentry error!");
  54. }
  55. `;
  56. const getDecoratedGlobalFilter =
  57. () => `import { Catch, ExceptionFilter } from '@nestjs/common';
  58. import { WithSentry } from '@sentry/nestjs';
  59. @Catch()
  60. export class YourCatchAllExceptionFilter implements ExceptionFilter {
  61. @WithSentry()
  62. catch(exception, host): void {
  63. // your implementation here
  64. }
  65. }
  66. `;
  67. const getAppModuleSnippetWithSentryGlobalFilter =
  68. () => `import { Module } from '@nestjs/common';
  69. import { APP_FILTER } from '@nestjs/core';
  70. import { SentryGlobalFilter } from '@sentry/nestjs/setup';
  71. @Module({
  72. providers: [
  73. {
  74. provide: APP_FILTER,
  75. useClass: SentryGlobalFilter,
  76. },
  77. // ..other providers
  78. ],
  79. })
  80. export class AppModule {}
  81. `;
  82. const onboarding: OnboardingConfig = {
  83. install: params => [
  84. {
  85. type: StepType.INSTALL,
  86. description: t('Add the Sentry NestJS SDK as a dependency:'),
  87. configurations: getInstallConfig(params, {
  88. basePackage: '@sentry/nestjs',
  89. }),
  90. },
  91. ],
  92. configure: params => [
  93. {
  94. type: StepType.CONFIGURE,
  95. description: t(
  96. "Initialize Sentry as early as possible in your application's lifecycle. Otherwise, auto-instrumentation will not work."
  97. ),
  98. configurations: [
  99. {
  100. description: tct(
  101. 'To initialize the SDK before everything else, create an external file called [code:instrument.js/mjs].',
  102. {code: <code />}
  103. ),
  104. code: [
  105. {
  106. label: 'JavaScript',
  107. value: 'javascript',
  108. language: 'javascript',
  109. filename: 'instrument.(js|ts)',
  110. code: getSdkInitSnippet(params, 'nestjs', 'esm'),
  111. },
  112. ],
  113. },
  114. {
  115. description: tct(
  116. 'Import [code1:instrument.js/mjs] in your [code2:main.ts/js] file:',
  117. {
  118. code1: <code />,
  119. code2: <code />,
  120. docs: (
  121. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nestjs/install/" />
  122. ),
  123. }
  124. ),
  125. code: [
  126. {
  127. label: 'JavaScript',
  128. value: 'javascript',
  129. language: 'javascript',
  130. filename: 'main.(js|ts)',
  131. code: getSdkSetupSnippet(),
  132. },
  133. ],
  134. },
  135. {
  136. description: tct(
  137. 'Afterwards, add the [code1:SentryModule] as a root module to your main module:',
  138. {
  139. code1: <code />,
  140. docs: (
  141. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nestjs/install/" />
  142. ),
  143. }
  144. ),
  145. code: [
  146. {
  147. label: 'JavaScript',
  148. value: 'javascript',
  149. language: 'javascript',
  150. filename: 'app.module.(js|ts)',
  151. code: getAppModuleSnippet(),
  152. },
  153. ],
  154. },
  155. {
  156. description: tct(
  157. 'In case you are using a global catch-all exception filter (which is either a filter registered with [code1:app.useGlobalFilters()] or a filter registered in your app module providers annotated with a [code2:@Catch()] decorator without arguments), add a [code3:@WithSentry()] decorator to the [code4:catch()] method of this global error filter. This decorator will report all unexpected errors that are received by your global error filter to Sentry:',
  158. {
  159. code1: <code />,
  160. code2: <code />,
  161. code3: <code />,
  162. code4: <code />,
  163. }
  164. ),
  165. code: [
  166. {
  167. label: 'JavaScript',
  168. value: 'javascript',
  169. language: 'javascript',
  170. filename: 'global.filter.(js|ts)',
  171. code: getDecoratedGlobalFilter(),
  172. },
  173. ],
  174. },
  175. {
  176. description: tct(
  177. 'In case you do not have a global catch-all exception filter, add the [code1:SentryGlobalFilter] to the providers of your main module. This filter will report all unhandled errors to Sentry that are not caught by any other error filter. Important: The [code2:SentryGlobalFilter] needs to be registered before any other exception filters.',
  178. {
  179. code1: <code />,
  180. code2: <code />,
  181. }
  182. ),
  183. code: [
  184. {
  185. label: 'JavaScript',
  186. value: 'javascript',
  187. language: 'javascript',
  188. filename: 'app.module.(js|ts)',
  189. code: getAppModuleSnippetWithSentryGlobalFilter(),
  190. },
  191. ],
  192. },
  193. ],
  194. },
  195. getUploadSourceMapsStep({
  196. guideLink: 'https://docs.sentry.io/platforms/javascript/guides/nestjs/sourcemaps/',
  197. ...params,
  198. }),
  199. ],
  200. verify: () => [
  201. {
  202. type: StepType.VERIFY,
  203. description: t(
  204. "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
  205. ),
  206. configurations: [
  207. {
  208. language: 'javascript',
  209. code: getVerifySnippet(),
  210. },
  211. ],
  212. },
  213. ],
  214. };
  215. const feedbackOnboardingNode: OnboardingConfig = {
  216. introduction: () => getCrashReportApiIntroduction(),
  217. install: () => [
  218. {
  219. type: StepType.INSTALL,
  220. description: getCrashReportInstallDescription(),
  221. configurations: [
  222. {
  223. code: [
  224. {
  225. label: 'JavaScript',
  226. value: 'javascript',
  227. language: 'javascript',
  228. code: `import * as Sentry from "@sentry/node";
  229. const eventId = Sentry.captureMessage("User Feedback");
  230. // OR: const eventId = Sentry.lastEventId();
  231. const userFeedback = {
  232. event_id: eventId,
  233. name: "John Doe",
  234. email: "john@doe.com",
  235. comments: "I really like your App, thanks!",
  236. };
  237. Sentry.captureUserFeedback(userFeedback);
  238. `,
  239. },
  240. ],
  241. },
  242. ],
  243. },
  244. ],
  245. configure: () => [],
  246. verify: () => [],
  247. nextSteps: () => [],
  248. };
  249. const crashReportOnboarding: OnboardingConfig = {
  250. introduction: () => getCrashReportModalIntroduction(),
  251. install: (params: Params) => getCrashReportJavaScriptInstallStep(params),
  252. configure: () => [
  253. {
  254. type: StepType.CONFIGURE,
  255. description: getCrashReportModalConfigDescription({
  256. link: 'https://docs.sentry.io/platforms/javascript/guides/nestjs/user-feedback/configuration/#crash-report-modal',
  257. }),
  258. },
  259. ],
  260. verify: () => [],
  261. nextSteps: () => [],
  262. };
  263. const docs: Docs = {
  264. onboarding,
  265. feedbackOnboardingCrashApi: feedbackOnboardingNode,
  266. customMetricsOnboarding: getJSServerMetricsOnboarding(),
  267. crashReportOnboarding,
  268. };
  269. export default docs;