Skip to content

Commit 5ca7f87

Browse files
committed
Updates Sentry.Sources to support multiple source code root paths
Before the changes in this commit Sentry.Sources only looked for source code files in one root path, the `:root_source_code_path`. With the changes in this commit this module will now be able to look for source code in multiple paths. The paths can be configured in the `:root_source_code_paths` config key. This change is specially important for umbrella applications [1], that have their code nested in the `apps` path. If we don't specify the root path for each individual application (which isn't possible without the changes in this commit), and instead just use `File.cwd!()` as the root path, the source code files of each umbrella app will be loaded with `apps/<app name>` prefix in their name. This is a problem because these names will never match the file names in the stacktrace, which means that Sentry won't be able to attach source code context. To avoid a configuration breaking change, the changes in this commit still support the `:root_source_code_path` configuration key, but "soft deprecate" it by removing it from documentation. This config key should be fully deprecated in the next major Sentry release. [1] https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-projects.html
1 parent b3a92b7 commit 5ca7f87

File tree

7 files changed

+73
-20
lines changed

7 files changed

+73
-20
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ config :sentry,
139139
environment_name: Mix.env(),
140140
included_environments: [:prod],
141141
enable_source_code_context: true,
142-
root_source_code_path: File.cwd!()
142+
root_source_code_paths: [File.cwd!()]
143143
```
144144

145145
The `environment_name` and `included_environments` work together to determine
@@ -169,7 +169,7 @@ The full range of options is the following:
169169
| `in_app_module_whitelist` | False | `[]` | |
170170
| `report_deps` | False | True | Will attempt to load Mix dependencies at compile time to report alongside events |
171171
| `enable_source_code_context` | False | False | |
172-
| `root_source_code_path` | Required if `enable_source_code_context` is enabled | | Should generally be set to `File.cwd!()`|
172+
| `root_source_code_paths` | Required if `enable_source_code_context` is enabled | | Should usually be set to `[File.cwd!()]`. For umbrella applications you should list all your applications paths in this list (e.g. `["#{File.cwd!()}/apps/app_1", "#{File.cwd!()}/apps/app_2"]`. |
173173
| `context_lines` | False | 3 | |
174174
| `source_code_exclude_patterns` | False | `[~r"/_build/", ~r"/deps/", ~r"/priv/"]` | |
175175
| `source_code_path_pattern` | False | `"**/*.ex"` | |

config/config.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ config :sentry,
55
environment_name: :dev,
66
tags: %{},
77
enable_source_code_context: true,
8-
root_source_code_path: File.cwd!()
8+
root_source_code_paths: [File.cwd!()]
99

1010
import_config "#{Mix.env()}.exs"

lib/sentry/config.ex

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,27 @@ defmodule Sentry.Config do
7777
get_config(:enable_source_code_context, default: false, check_dsn: false)
7878
end
7979

80-
def root_source_code_path do
80+
# :root_source_code_path (single path) was replaced by :root_source_code_paths (list of
81+
# paths).
82+
#
83+
# In order for this to not be a breaking change we still accept the old
84+
# :root_source_code_path as a fallback.
85+
#
86+
# We should deprecate this the :root_source_code_path completely in the next major
87+
# release.
88+
def root_source_code_paths do
89+
paths = get_config(:root_source_code_paths)
8190
path = get_config(:root_source_code_path)
8291

83-
if path do
84-
path
85-
else
86-
raise ArgumentError.exception(":root_source_code_path must be configured")
92+
cond do
93+
not is_nil(paths) ->
94+
paths
95+
96+
not is_nil(path) ->
97+
[path]
98+
99+
true ->
100+
raise ArgumentError.exception(":root_source_code_paths must be configured")
87101
end
88102
end
89103

lib/sentry/sources.ex

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ defmodule Sentry.Sources do
88
99
### Configuration
1010
There is configuration required to set up this functionality. The options
11-
include `:enable_source_code_context`, `:root_source_code_path`, `:context_lines`,
11+
include `:enable_source_code_context`, `:root_source_code_paths`, `:context_lines`,
1212
`:source_code_exclude_patterns`, and `:source_code_path_pattern`.
1313
1414
* `:enable_source_code_context` - when `true`, enables reporting source code
1515
alongside exceptions.
16-
* `:root_source_code_path` - The path from which to start recursively reading files from.
17-
Should usually be set to `File.cwd!()`.
16+
* `:root_source_code_paths` - List of paths from which to start recursively reading files from.
17+
Should usually be set to `[File.cwd!()]`. For umbrella applications you should list all your
18+
applications paths in this list (e.g. `["#{File.cwd!()}/apps/app_1", "#{File.cwd!()}/apps/app_2"]`.
1819
* `:context_lines` - The number of lines of source code before and after the line that
1920
caused the exception to be included. Defaults to `3`.
2021
* `:source_code_exclude_patterns` - a list of Regex expressions used to exclude file paths that
@@ -28,7 +29,7 @@ defmodule Sentry.Sources do
2829
config :sentry,
2930
dsn: "https://public:[email protected]/1",
3031
enable_source_code_context: true,
31-
root_source_code_path: File.cwd!(),
32+
root_source_code_path: [File.cwd!()],
3233
context_lines: 5
3334
3435
### Source code storage
@@ -64,18 +65,20 @@ defmodule Sentry.Sources do
6465
@type source_map :: %{String.t() => file_map}
6566

6667
def load_files do
67-
root_path = Config.root_source_code_path()
68+
root_paths = Config.root_source_code_paths()
6869
path_pattern = Config.source_code_path_pattern()
6970
exclude_patterns = Config.source_code_exclude_patterns()
7071

71-
Path.join(root_path, path_pattern)
72-
|> Path.wildcard()
73-
|> exclude_files(exclude_patterns)
74-
|> Enum.reduce(%{}, fn path, acc ->
75-
key = Path.relative_to(path, root_path)
76-
value = source_to_lines(File.read!(path))
72+
Enum.reduce(root_paths, %{}, fn root_path, acc1 ->
73+
Path.join(root_path, path_pattern)
74+
|> Path.wildcard()
75+
|> exclude_files(exclude_patterns)
76+
|> Enum.reduce(acc1, fn path, acc2 ->
77+
key = Path.relative_to(path, root_path)
78+
value = source_to_lines(File.read!(path))
7779

78-
Map.put(acc, key, value)
80+
Map.put(acc2, key, value)
81+
end)
7982
end)
8083
end
8184

test/sources_test.exs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,32 @@ defmodule Sentry.SourcesTest do
33
use Plug.Test
44
import Sentry.TestEnvironmentHelper
55

6+
describe "load_files/0" do
7+
test "loads files" do
8+
Application.put_env(:sentry, :root_source_code_paths, [
9+
File.cwd!() <> "/test/support/example-umbrella-app/apps/app_a",
10+
File.cwd!() <> "/test/support/example-umbrella-app/apps/app_b"
11+
])
12+
13+
assert %{
14+
"lib/module_a.ex" => %{
15+
1 => "defmodule ModuleA do",
16+
2 => " def test do",
17+
3 => " \"test a\"",
18+
4 => " end",
19+
5 => "end"
20+
},
21+
"lib/module_b.ex" => %{
22+
1 => "defmodule ModuleB do",
23+
2 => " def test do",
24+
3 => " \"test b\"",
25+
4 => " end",
26+
5 => "end"
27+
}
28+
} = Sentry.Sources.load_files()
29+
end
30+
end
31+
632
test "exception makes call to Sentry API" do
733
correct_context = %{
834
"context_line" => " raise RuntimeError, \"Error\"",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
defmodule ModuleA do
2+
def test do
3+
"test a"
4+
end
5+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
defmodule ModuleB do
2+
def test do
3+
"test b"
4+
end
5+
end

0 commit comments

Comments
 (0)