From 4c33d3f0aa50c488d473530495886c81142c39c3 Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Wed, 1 Oct 2025 13:34:09 +0300 Subject: [PATCH] Enable Sentry --- Dockerfile | 3 +++ config/config.exs | 6 ++++++ config/runtime.exs | 9 +++++++++ lib/music_library/application.ex | 4 ++++ lib/music_library_web/endpoint.ex | 3 +++ lib/sentry/finch_client.ex | 25 +++++++++++++++++++++++++ mix.exs | 1 + mix.lock | 2 ++ 8 files changed, 53 insertions(+) create mode 100644 lib/sentry/finch_client.ex diff --git a/Dockerfile b/Dockerfile index 4b700c96..3516d2c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -70,6 +70,9 @@ RUN cd assets && npm install && cd .. # Compile the release and assets RUN mix do compile, assets.deploy +# Make sure stacktraces are complete +RUN mix sentry.package_source_code + # Changes to config/runtime.exs don't require recompiling the code COPY config/runtime.exs config/ diff --git a/config/config.exs b/config/config.exs index 665a90b0..103dab18 100644 --- a/config/config.exs +++ b/config/config.exs @@ -100,6 +100,12 @@ config :music_library, MusicLibrary.BackgroundRepo, priv: "priv/background_repo" config :fluxon, :translate_function, &MusicLibraryWeb.CoreComponents.translate_error/1 +config :sentry, + client: Sentry.FinchClient, + environment_name: config_env(), + enable_source_code_context: true, + root_source_code_paths: [File.cwd!()] + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{config_env()}.exs" diff --git a/config/runtime.exs b/config/runtime.exs index a5e3cf1a..4bd3ff90 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -153,6 +153,15 @@ if config_env() == :prod do ], secret_key_base: secret_key_base + sentry_dsn = + System.get_env("SENTRY_DSN") || + raise """ + environment variable SENTRY_DSN is missing. + """ + + config :sentry, + dsn: sentry_dsn + # ## SSL Support # # To get SSL working, you will need to add the `https` key diff --git a/lib/music_library/application.ex b/lib/music_library/application.ex index 48ee1f61..eff5ca89 100644 --- a/lib/music_library/application.ex +++ b/lib/music_library/application.ex @@ -9,6 +9,10 @@ defmodule MusicLibrary.Application do @impl true def start(_type, _args) do + :logger.add_handler(:my_sentry_handler, Sentry.LoggerHandler, %{ + config: %{metadata: [:file, :line]} + }) + _ = Assets.Cache.new() children = [ diff --git a/lib/music_library_web/endpoint.ex b/lib/music_library_web/endpoint.ex index b4391192..47e5865a 100644 --- a/lib/music_library_web/endpoint.ex +++ b/lib/music_library_web/endpoint.ex @@ -1,4 +1,5 @@ defmodule MusicLibraryWeb.Endpoint do + use Sentry.PlugCapture use Phoenix.Endpoint, otp_app: :music_library # The session will be stored in the cookie and signed, @@ -55,6 +56,8 @@ defmodule MusicLibraryWeb.Endpoint do pass: ["*/*"], json_decoder: Phoenix.json_library() + plug Sentry.PlugContext + plug Plug.MethodOverride plug Plug.Head plug Plug.Session, @session_options diff --git a/lib/sentry/finch_client.ex b/lib/sentry/finch_client.ex new file mode 100644 index 00000000..ae81c0a6 --- /dev/null +++ b/lib/sentry/finch_client.ex @@ -0,0 +1,25 @@ +defmodule Sentry.FinchClient do + @moduledoc """ + Defines a small shim to use `Finch` as a `Sentry.HTTPClient`. + """ + + @behaviour Sentry.HTTPClient + + @impl true + def child_spec do + Finch.child_spec(name: Sentry.Finch) + end + + @impl true + def post(url, headers, body) do + request = Finch.build(:post, url, headers, body) + + case Finch.request(request, Sentry.Finch) do + {:ok, response} -> + {:ok, response.status, response.headers, response.body} + + error -> + error + end + end +end diff --git a/mix.exs b/mix.exs index 0ef5e0b8..57f3bf66 100644 --- a/mix.exs +++ b/mix.exs @@ -109,6 +109,7 @@ defmodule MusicLibrary.MixProject do {:lazy_html, ">= 0.1.0", only: :test}, # Prod error/perf tooling + {:sentry, "~> 11.0"}, {:phoenix_live_dashboard, "~> 0.8.3"}, {:error_tracker, "~> 0.6.0"}, {:recon, "~> 2.5"}, diff --git a/mix.lock b/mix.lock index 59cef976..68a5f106 100644 --- a/mix.lock +++ b/mix.lock @@ -35,6 +35,7 @@ "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, + "nimble_ownership": {:hex, :nimble_ownership, "1.0.1", "f69fae0cdd451b1614364013544e66e4f5d25f36a2056a9698b793305c5aa3a6", [:mix], [], "hexpm", "3825e461025464f519f3f3e4a1f9b68c47dc151369611629ad08b636b73bb22d"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "oban": {:hex, :oban, "2.20.1", "39d0b68787e5cf251541c0d657a698f6142a24d8744e1e40b2cf045d4fa232a6", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.20", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.3", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17a45277dbeb41a455040b41dd8c467163fad685d1366f2f59207def3bcdd1d8"}, @@ -57,6 +58,7 @@ "recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"}, "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, + "sentry": {:hex, :sentry, "11.0.4", "60371c96cefd247e0fc98840bba2648f64f19aa0b8db8e938f5a98421f55b619", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 0.3.0 or ~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:opentelemetry, ">= 0.0.0", [hex: :opentelemetry, repo: "hexpm", optional: true]}, {:opentelemetry_api, ">= 0.0.0", [hex: :opentelemetry_api, repo: "hexpm", optional: true]}, {:opentelemetry_exporter, ">= 0.0.0", [hex: :opentelemetry_exporter, repo: "hexpm", optional: true]}, {:opentelemetry_semantic_conventions, ">= 0.0.0", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "feaafc284dc204c82aadaddc884227aeaa3480decb274d30e184b9d41a700c66"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "table_rex": {:hex, :table_rex, "4.1.0", "fbaa8b1ce154c9772012bf445bfb86b587430fb96f3b12022d3f35ee4a68c918", [:mix], [], "hexpm", "95932701df195d43bc2d1c6531178fc8338aa8f38c80f098504d529c43bc2601"},