nestjs.tsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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 [code: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 [code:SentryGlobalFilter] needs to be registered before any other exception filters. Also note that in NestJS + GraphQL applications the [code:SentryGlobalFilter] needs to be replaced with the [code:SentryGlobalGraphQLFilter].',
  178. {
  179. code: <code />,
  180. }
  181. ),
  182. code: [
  183. {
  184. label: 'JavaScript',
  185. value: 'javascript',
  186. language: 'javascript',
  187. filename: 'app.module.(js|ts)',
  188. code: getAppModuleSnippetWithSentryGlobalFilter(),
  189. },
  190. ],
  191. },
  192. ],
  193. },
  194. getUploadSourceMapsStep({
  195. guideLink: 'https://docs.sentry.io/platforms/javascript/guides/nestjs/sourcemaps/',
  196. ...params,
  197. }),
  198. ],
  199. verify: () => [
  200. {
  201. type: StepType.VERIFY,
  202. description: t(
  203. "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
  204. ),
  205. configurations: [
  206. {
  207. language: 'javascript',
  208. code: getVerifySnippet(),
  209. },
  210. ],
  211. },
  212. ],
  213. };
  214. const feedbackOnboardingNode: OnboardingConfig = {
  215. introduction: () => getCrashReportApiIntroduction(),
  216. install: () => [
  217. {
  218. type: StepType.INSTALL,
  219. description: getCrashReportInstallDescription(),
  220. configurations: [
  221. {
  222. code: [
  223. {
  224. label: 'JavaScript',
  225. value: 'javascript',
  226. language: 'javascript',
  227. code: `import * as Sentry from "@sentry/node";
  228. const eventId = Sentry.captureMessage("User Feedback");
  229. // OR: const eventId = Sentry.lastEventId();
  230. const userFeedback = {
  231. event_id: eventId,
  232. name: "John Doe",
  233. email: "john@doe.com",
  234. comments: "I really like your App, thanks!",
  235. };
  236. Sentry.captureUserFeedback(userFeedback);
  237. `,
  238. },
  239. ],
  240. },
  241. ],
  242. },
  243. ],
  244. configure: () => [],
  245. verify: () => [],
  246. nextSteps: () => [],
  247. };
  248. const crashReportOnboarding: OnboardingConfig = {
  249. introduction: () => getCrashReportModalIntroduction(),
  250. install: (params: Params) => getCrashReportJavaScriptInstallStep(params),
  251. configure: () => [
  252. {
  253. type: StepType.CONFIGURE,
  254. description: getCrashReportModalConfigDescription({
  255. link: 'https://docs.sentry.io/platforms/javascript/guides/nestjs/user-feedback/configuration/#crash-report-modal',
  256. }),
  257. },
  258. ],
  259. verify: () => [],
  260. nextSteps: () => [],
  261. };
  262. const docs: Docs = {
  263. onboarding,
  264. feedbackOnboardingCrashApi: feedbackOnboardingNode,
  265. customMetricsOnboarding: getJSServerMetricsOnboarding(),
  266. crashReportOnboarding,
  267. };
  268. export default docs;