elixir.tsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import {Fragment} from 'react';
  2. import ExternalLink from 'sentry/components/links/externalLink';
  3. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  4. import type {
  5. Docs,
  6. DocsParams,
  7. OnboardingConfig,
  8. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  9. import {t, tct} from 'sentry/locale';
  10. type Params = DocsParams;
  11. const getInstallSnippet = () => `
  12. defp deps do
  13. [
  14. # ...
  15. {:sentry, "~> 8.0"},
  16. {:jason, "~> 1.1"},
  17. {:hackney, "~> 1.8"},
  18. # if you are using plug_cowboy
  19. {:plug_cowboy, "~> 2.3"}
  20. ]
  21. end`;
  22. const getConfigureSnippet = (params: Params) => `
  23. config :sentry,
  24. dsn: "${params.dsn}",
  25. environment_name: :prod,
  26. enable_source_code_context: true,
  27. root_source_code_path: File.cwd!(),
  28. tags: %{
  29. env: "production"
  30. },
  31. included_environments: [:prod]`;
  32. const getConfigureSnippetMixEnv = (params: Params) => `
  33. config :sentry, dsn: "${params.dsn}",
  34. included_environments: [:prod],
  35. environment_name: Mix.env`;
  36. const getCustomEnvironmentNameSnippet = (params: Params) => `
  37. config :sentry, dsn: "${params.dsn}",
  38. included_environments: ~w(production staging),
  39. environment_name: System.get_env("RELEASE_LEVEL") || "development"`;
  40. const getConfigureRouterSnippet = () => `
  41. # Phoenix
  42. use Sentry.PlugCapture
  43. use Phoenix.Endpoint, otp_app: :my_app
  44. # ...
  45. plug Plug.Parsers,
  46. parsers: [:urlencoded, :multipart, :json],
  47. pass: ["*/*"],
  48. json_decoder: Phoenix.json_library()
  49. plug Sentry.PlugContext
  50. # Plug
  51. use Plug.Router
  52. use Sentry.PlugCapture
  53. # ...
  54. plug Plug.Parsers,
  55. parsers: [:urlencoded, :multipart, :json],
  56. pass: ["*/*"],
  57. json_decoder: Phoenix.json_library()
  58. plug Sentry.PlugContext`;
  59. const getCaptureExceptionSnippet = () => `
  60. # lib/my_app/application.ex
  61. def start(_type, _args) do
  62. Logger.add_backend(Sentry.LoggerBackend)`;
  63. const getCaptureErrorsSnippet = () => `
  64. try do
  65. ThisWillError.really()
  66. rescue
  67. my_exception ->
  68. Sentry.capture_exception(my_exception, [stacktrace: __STACKTRACE__, extra: %{extra: information}])
  69. end`;
  70. const onboarding: OnboardingConfig = {
  71. install: () => [
  72. {
  73. type: StepType.INSTALL,
  74. description: tct(
  75. 'Edit your [mixCode:mix.exs] file to add it as a dependency and add the [sentryCode::sentry] package to your applications:',
  76. {sentryCode: <code />, mixCode: <code />}
  77. ),
  78. configurations: [
  79. {
  80. language: 'elixir',
  81. description: <p>{tct('Install [code:sentry-sdk]:', {code: <code />})}</p>,
  82. code: getInstallSnippet(),
  83. },
  84. ],
  85. },
  86. ],
  87. configure: params => [
  88. {
  89. type: StepType.CONFIGURE,
  90. description: tct(
  91. 'Setup the application production environment in your [code:config/prod.exs]',
  92. {
  93. code: <code />,
  94. }
  95. ),
  96. configurations: [
  97. {
  98. language: 'elixir',
  99. code: getConfigureSnippet(params),
  100. },
  101. {
  102. description: (
  103. <Fragment>
  104. <p>
  105. {tct(
  106. 'The [environmentNameCode:environment_name] and [includedEnvironmentsCode:included_environments] work together to determine if and when Sentry should record exceptions. The [environmentNameCode:environment_name] is the name of the current environment. In the example above, we have explicitly set the environment to [prodCode::prod] which works well if you are inside an environment specific configuration like [configCode:config/prod.exs].',
  107. {
  108. environmentNameCode: <code />,
  109. includedEnvironmentsCode: <code />,
  110. prodCode: <code />,
  111. configCode: <code />,
  112. }
  113. )}
  114. </p>
  115. <p>
  116. {tct(
  117. 'An alternative is to use [code:Mix.env] in your general configuration file:',
  118. {code: <code />}
  119. )}
  120. </p>
  121. </Fragment>
  122. ),
  123. configurations: [
  124. {
  125. language: 'elixir',
  126. code: getConfigureSnippetMixEnv(params),
  127. },
  128. ],
  129. },
  130. {
  131. description: (
  132. <Fragment>
  133. <p>
  134. {tct(
  135. 'This will set the environment name to whatever the current Mix environment atom is, but it will only send events if the current environment is [prodCode::prod], since that is the only entry in the [includedEnvironmentsCode:included_environments] key.',
  136. {
  137. prodCode: <code />,
  138. includedEnvironmentsCode: <code />,
  139. }
  140. )}
  141. </p>
  142. {t(
  143. "You can even rely on more custom determinations of the environment name. It's not uncommon for most applications to have a 'staging' environment. In order to handle this without adding an additional Mix environment, you can set an environment variable that determines the release level."
  144. )}
  145. </Fragment>
  146. ),
  147. language: 'elixir',
  148. code: getCustomEnvironmentNameSnippet(params),
  149. },
  150. {
  151. description: (
  152. <Fragment>
  153. <p>
  154. {tct(
  155. "In this example, we are getting the environment name from the [code:RELEASE_LEVEL] environment variable. If that variable does not exist, it will default to [code:'development']. Now, on our servers, we can set the environment variable appropriately. On our local development machines, exceptions will never be sent, because the default value is not in the list of [code:included_environments].",
  156. {
  157. code: <code />,
  158. }
  159. )}
  160. </p>
  161. <p>
  162. {tct(
  163. 'If using an environment with Plug or Phoenix, add the following to [plugRouterCode:Plug.Router] or [phoenixEndpointCode:Phoenix.Endpoint]:',
  164. {plugRouterCode: <code />, phoenixEndpointCode: <code />}
  165. )}
  166. </p>
  167. </Fragment>
  168. ),
  169. language: 'elixir',
  170. code: getConfigureRouterSnippet(),
  171. additionalInfo: tct(
  172. '[sentryPlugContextCode:Sentry.PlugContext] gathers the contextual information for errors, and [sentryPlugCaptureCode:Sentry.PlugCapture] captures and sends any errors that occur in the Plug stack. [sentryPlugContextCode:Sentry.PlugContext] should be below [sentryPlugParsersCode:Plug.Parsers] if you are using it.',
  173. {
  174. sentryPlugCaptureCode: <code />,
  175. sentryPlugContextCode: <code />,
  176. sentryPlugParsersCode: <code />,
  177. }
  178. ),
  179. },
  180. ],
  181. },
  182. {
  183. title: t('Capture Crashed Process Exceptions'),
  184. description: tct(
  185. 'This library comes with an extension to capture all error messages that the Plug handler might not. This is based on [link:Logger.Backend]. You can add it as a backend when your application starts:',
  186. {
  187. link: (
  188. <ExternalLink href="https://hexdocs.pm/logger/Logger.html#module-backends" />
  189. ),
  190. }
  191. ),
  192. configurations: [
  193. {
  194. language: 'elixir',
  195. code: getCaptureExceptionSnippet(),
  196. },
  197. ],
  198. },
  199. {
  200. title: t('Capturing Errors'),
  201. description: (
  202. <Fragment>
  203. {t(
  204. 'If you use the LoggerBackend and set up the Plug/Phoenix integrations, all errors will bubble up to Sentry.'
  205. )}
  206. <p>{t('Otherwise, we provide a simple way to capture exceptions manually:')}</p>
  207. </Fragment>
  208. ),
  209. configurations: [
  210. {
  211. language: 'elixir',
  212. code: getCaptureErrorsSnippet(),
  213. },
  214. ],
  215. },
  216. ],
  217. verify: () => [],
  218. };
  219. const docs: Docs = {
  220. onboarding,
  221. };
  222. export default docs;