Browse Source

ref(getting-started-docs): Migrate elixir doc to sentry main repo (#53141)

Priscila Oliveira 1 year ago
parent
commit
000a8cf7c3

+ 1 - 0
static/app/components/onboarding/gettingStartedDoc/sdkDocumentation.tsx

@@ -55,6 +55,7 @@ export const migratedDocs = [
   'node',
   'node-express',
   'electron',
+  'elixir',
 ];
 
 type SdkDocumentationProps = {

+ 1 - 1
static/app/gettingStartedDocs/electron/electron.spec.tsx

@@ -5,7 +5,7 @@ import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
 import {GettingStartedWithElectron, steps} from './electron';
 
 describe('GettingStartedWithElectron', function () {
-  it('all products are selected', function () {
+  it('renders doc correctly', function () {
     const {container} = render(<GettingStartedWithElectron dsn="test-dsn" />);
 
     // Steps

+ 20 - 0
static/app/gettingStartedDocs/elixir/elixir.spec.tsx

@@ -0,0 +1,20 @@
+import {render, screen} from 'sentry-test/reactTestingLibrary';
+
+import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
+
+import {GettingStartedWithElixir, steps} from './elixir';
+
+describe('GettingStartedWithElixir', function () {
+  it('renders doc correctly', function () {
+    const {container} = render(<GettingStartedWithElixir dsn="test-dsn" />);
+
+    // Steps
+    for (const step of steps()) {
+      expect(
+        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
+      ).toBeInTheDocument();
+    }
+
+    expect(container).toSnapshot();
+  });
+});

+ 240 - 0
static/app/gettingStartedDocs/elixir/elixir.tsx

@@ -0,0 +1,240 @@
+import {Fragment} from 'react';
+
+import ExternalLink from 'sentry/components/links/externalLink';
+import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
+import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
+import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {t, tct} from 'sentry/locale';
+
+// Configuration Start
+export const steps = ({
+  dsn,
+}: {
+  dsn?: string;
+} = {}): LayoutProps['steps'] => [
+  {
+    type: StepType.INSTALL,
+    description: (
+      <p>
+        {tct(
+          'Edit your [mixCode:mix.exs] file to add it as a dependency and add the [sentryCode::sentry] package to your applications:',
+          {sentryCode: <code />, mixCode: <code />}
+        )}
+      </p>
+    ),
+    configurations: [
+      {
+        language: 'elixir',
+        description: <p>{tct('Install [code:sentry-sdk]:', {code: <code />})}</p>,
+        code: `
+defp deps do
+  [
+    # ...
+    {:sentry, "~> 8.0"},
+    {:jason, "~> 1.1"},
+    {:hackney, "~> 1.8"},
+    # if you are using plug_cowboy
+    {:plug_cowboy, "~> 2.3"}
+  ]
+end
+        `,
+      },
+    ],
+  },
+  {
+    type: StepType.CONFIGURE,
+    description: (
+      <p>
+        {tct(
+          'Setup the application production environment in your [code:config/prod.exs]',
+          {
+            code: <code />,
+          }
+        )}
+      </p>
+    ),
+    configurations: [
+      {
+        language: 'elixir',
+        code: `
+config :sentry,
+dsn: "${dsn}",
+environment_name: :prod,
+enable_source_code_context: true,
+root_source_code_path: File.cwd!(),
+tags: %{
+  env: "production"
+},
+included_environments: [:prod]
+        `,
+      },
+      {
+        description: (
+          <Fragment>
+            <p>
+              {tct(
+                '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].',
+                {
+                  environmentNameCode: <code />,
+                  includedEnvironmentsCode: <code />,
+                  prodCode: <code />,
+                  configCode: <code />,
+                }
+              )}
+            </p>
+            <p>
+              {tct(
+                'An alternative is to use [code:Mix.env] in your general configuration file:',
+                {code: <code />}
+              )}
+            </p>
+          </Fragment>
+        ),
+        configurations: [
+          {
+            language: 'elixir',
+            code: `
+config :sentry, dsn: "${dsn}",
+included_environments: [:prod],
+environment_name: Mix.env
+            `,
+          },
+        ],
+      },
+      {
+        description: (
+          <Fragment>
+            <p>
+              {tct(
+                '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.',
+                {
+                  prodCode: <code />,
+                  includedEnvironmentsCode: <code />,
+                }
+              )}
+            </p>
+            {t(
+              "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."
+            )}
+          </Fragment>
+        ),
+        language: 'elixir',
+        code: `
+config :sentry, dsn: "${dsn}",
+included_environments: ~w(production staging),
+environment_name: System.get_env("RELEASE_LEVEL") || "development"
+        `,
+      },
+      {
+        description: (
+          <Fragment>
+            <p>
+              {tct(
+                "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].",
+                {
+                  code: <code />,
+                }
+              )}
+            </p>
+            <p>
+              {tct(
+                'If using an environment with Plug or Phoenix, add the following to [codePlugRouter:Plug.Router] or [codePhoenixEndpoint:Phoenix.Endpoint]:',
+                {codePlugRouter: <code />, codePhoenixEndpoint: <code />}
+              )}
+            </p>
+          </Fragment>
+        ),
+        language: 'elixir',
+        code: `
+# Phoenix
+use Sentry.PlugCapture
+use Phoenix.Endpoint, otp_app: :my_app
+# ...
+plug Plug.Parsers,
+  parsers: [:urlencoded, :multipart, :json],
+  pass: ["*/*"],
+  json_decoder: Phoenix.json_library()
+plug Sentry.PlugContext
+# Plug
+use Plug.Router
+use Sentry.PlugCapture
+# ...
+plug Plug.Parsers,
+  parsers: [:urlencoded, :multipart, :json],
+  pass: ["*/*"],
+  json_decoder: Phoenix.json_library()
+plug Sentry.PlugContext
+        `,
+        additionalInfo: (
+          <p>
+            {tct(
+              '[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.',
+              {
+                sentryPlugCaptureCode: <code />,
+                sentryPlugContextCode: <code />,
+                sentryPlugParsersCode: <code />,
+              }
+            )}
+          </p>
+        ),
+      },
+    ],
+  },
+  {
+    title: t('Capture Crashed Process Exceptions'),
+    description: (
+      <p>
+        {tct(
+          '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:',
+          {
+            link: (
+              <ExternalLink href="https://hexdocs.pm/logger/Logger.html#module-backends" />
+            ),
+          }
+        )}
+      </p>
+    ),
+    configurations: [
+      {
+        language: 'elixir',
+        code: `
+# lib/my_app/application.ex
+
+def start(_type, _args) do
+  Logger.add_backend(Sentry.LoggerBackend)
+        `,
+      },
+    ],
+  },
+  {
+    title: t('Capturing Errors'),
+    description: (
+      <Fragment>
+        {t(
+          'If you use the LoggerBackend and set up the Plug/Phoenix integrations, all errors will bubble up to Sentry.'
+        )}
+        <p>{t('Otherwise, we provide a simple way to capture exceptions manually:')}</p>
+      </Fragment>
+    ),
+    configurations: [
+      {
+        language: 'elixir',
+        code: `
+try do
+  ThisWillError.really()
+rescue
+  my_exception ->
+    Sentry.capture_exception(my_exception, [stacktrace: __STACKTRACE__, extra: %{extra: information}])
+end
+        `,
+      },
+    ],
+  },
+];
+// Configuration End
+
+export function GettingStartedWithElixir({dsn, ...props}: ModuleProps) {
+  return <Layout steps={steps({dsn})} {...props} />;
+}
+
+export default GettingStartedWithElixir;

+ 1 - 1
static/app/gettingStartedDocs/node/express.spec.tsx

@@ -5,7 +5,7 @@ import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
 import {GettingStartedWithExpress, steps} from './express';
 
 describe('GettingStartedWithExpress', function () {
-  it('all products are selected', function () {
+  it('renders doc correctly', function () {
     const {container} = render(<GettingStartedWithExpress dsn="test-dsn" />);
 
     // Steps

+ 1 - 1
static/app/gettingStartedDocs/node/node.spec.tsx

@@ -5,7 +5,7 @@ import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
 import {GettingStartedWithNode, steps} from './node';
 
 describe('GettingStartedWithNode', function () {
-  it('all products are selected', function () {
+  it('renders doc correctly', function () {
     const {container} = render(<GettingStartedWithNode dsn="test-dsn" />);
 
     // Steps