elixir.tsx 7.4 KB

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