elixir.tsx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import {Fragment} from 'react';
  2. import ExternalLink from 'sentry/components/links/externalLink';
  3. import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
  4. import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
  5. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  6. import {t, tct} from 'sentry/locale';
  7. // Configuration Start
  8. export const steps = ({
  9. dsn,
  10. }: Partial<Pick<ModuleProps, 'dsn'>> = {}): LayoutProps['steps'] => [
  11. {
  12. type: StepType.INSTALL,
  13. description: (
  14. <p>
  15. {tct(
  16. 'Edit your [mixCode:mix.exs] file to add it as a dependency and add the [sentryCode::sentry] package to your applications:',
  17. {sentryCode: <code />, mixCode: <code />}
  18. )}
  19. </p>
  20. ),
  21. configurations: [
  22. {
  23. language: 'elixir',
  24. description: <p>{tct('Install [code:sentry-sdk]:', {code: <code />})}</p>,
  25. code: `
  26. defp deps do
  27. [
  28. # ...
  29. {:sentry, "~> 8.0"},
  30. {:jason, "~> 1.1"},
  31. {:hackney, "~> 1.8"},
  32. # if you are using plug_cowboy
  33. {:plug_cowboy, "~> 2.3"}
  34. ]
  35. end
  36. `,
  37. },
  38. ],
  39. },
  40. {
  41. type: StepType.CONFIGURE,
  42. description: (
  43. <p>
  44. {tct(
  45. 'Setup the application production environment in your [code:config/prod.exs]',
  46. {
  47. code: <code />,
  48. }
  49. )}
  50. </p>
  51. ),
  52. configurations: [
  53. {
  54. language: 'elixir',
  55. code: `
  56. config :sentry,
  57. dsn: "${dsn}",
  58. environment_name: :prod,
  59. enable_source_code_context: true,
  60. root_source_code_path: File.cwd!(),
  61. tags: %{
  62. env: "production"
  63. },
  64. included_environments: [:prod]
  65. `,
  66. },
  67. {
  68. description: (
  69. <Fragment>
  70. <p>
  71. {tct(
  72. '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].',
  73. {
  74. environmentNameCode: <code />,
  75. includedEnvironmentsCode: <code />,
  76. prodCode: <code />,
  77. configCode: <code />,
  78. }
  79. )}
  80. </p>
  81. <p>
  82. {tct(
  83. 'An alternative is to use [code:Mix.env] in your general configuration file:',
  84. {code: <code />}
  85. )}
  86. </p>
  87. </Fragment>
  88. ),
  89. configurations: [
  90. {
  91. language: 'elixir',
  92. code: `
  93. config :sentry, dsn: "${dsn}",
  94. included_environments: [:prod],
  95. environment_name: Mix.env
  96. `,
  97. },
  98. ],
  99. },
  100. {
  101. description: (
  102. <Fragment>
  103. <p>
  104. {tct(
  105. '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.',
  106. {
  107. prodCode: <code />,
  108. includedEnvironmentsCode: <code />,
  109. }
  110. )}
  111. </p>
  112. {t(
  113. "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."
  114. )}
  115. </Fragment>
  116. ),
  117. language: 'elixir',
  118. code: `
  119. config :sentry, dsn: "${dsn}",
  120. included_environments: ~w(production staging),
  121. environment_name: System.get_env("RELEASE_LEVEL") || "development"
  122. `,
  123. },
  124. {
  125. description: (
  126. <Fragment>
  127. <p>
  128. {tct(
  129. "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].",
  130. {
  131. code: <code />,
  132. }
  133. )}
  134. </p>
  135. <p>
  136. {tct(
  137. 'If using an environment with Plug or Phoenix, add the following to [plugRouterCode:Plug.Router] or [phoenixEndpointCode:Phoenix.Endpoint]:',
  138. {plugRouterCode: <code />, phoenixEndpointCode: <code />}
  139. )}
  140. </p>
  141. </Fragment>
  142. ),
  143. language: 'elixir',
  144. code: `
  145. # Phoenix
  146. use Sentry.PlugCapture
  147. use Phoenix.Endpoint, otp_app: :my_app
  148. # ...
  149. plug Plug.Parsers,
  150. parsers: [:urlencoded, :multipart, :json],
  151. pass: ["*/*"],
  152. json_decoder: Phoenix.json_library()
  153. plug Sentry.PlugContext
  154. # Plug
  155. use Plug.Router
  156. use Sentry.PlugCapture
  157. # ...
  158. plug Plug.Parsers,
  159. parsers: [:urlencoded, :multipart, :json],
  160. pass: ["*/*"],
  161. json_decoder: Phoenix.json_library()
  162. plug Sentry.PlugContext
  163. `,
  164. additionalInfo: (
  165. <p>
  166. {tct(
  167. '[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.',
  168. {
  169. sentryPlugCaptureCode: <code />,
  170. sentryPlugContextCode: <code />,
  171. sentryPlugParsersCode: <code />,
  172. }
  173. )}
  174. </p>
  175. ),
  176. },
  177. ],
  178. },
  179. {
  180. title: t('Capture Crashed Process Exceptions'),
  181. description: (
  182. <p>
  183. {tct(
  184. '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:',
  185. {
  186. link: (
  187. <ExternalLink href="https://hexdocs.pm/logger/Logger.html#module-backends" />
  188. ),
  189. }
  190. )}
  191. </p>
  192. ),
  193. configurations: [
  194. {
  195. language: 'elixir',
  196. code: `
  197. # lib/my_app/application.ex
  198. def start(_type, _args) do
  199. Logger.add_backend(Sentry.LoggerBackend)
  200. `,
  201. },
  202. ],
  203. },
  204. {
  205. title: t('Capturing Errors'),
  206. description: (
  207. <Fragment>
  208. {t(
  209. 'If you use the LoggerBackend and set up the Plug/Phoenix integrations, all errors will bubble up to Sentry.'
  210. )}
  211. <p>{t('Otherwise, we provide a simple way to capture exceptions manually:')}</p>
  212. </Fragment>
  213. ),
  214. configurations: [
  215. {
  216. language: 'elixir',
  217. code: `
  218. try do
  219. ThisWillError.really()
  220. rescue
  221. my_exception ->
  222. Sentry.capture_exception(my_exception, [stacktrace: __STACKTRACE__, extra: %{extra: information}])
  223. end
  224. `,
  225. },
  226. ],
  227. },
  228. ];
  229. // Configuration End
  230. export function GettingStartedWithElixir({dsn, ...props}: ModuleProps) {
  231. return <Layout steps={steps({dsn})} {...props} />;
  232. }
  233. export default GettingStartedWithElixir;