Skip to content

Commit 3064362

Browse files
committed
wip - e2e tests for distributed tracing
1 parent bbdc484 commit 3064362

File tree

8 files changed

+116
-2
lines changed

8 files changed

+116
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ test_integrations/phoenix_app/db
1717

1818
test_integrations/*/_build
1919
test_integrations/*/deps
20+
test_integrations/*/test-results/

mix.exs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,11 @@ defmodule Sentry.Mixfile do
145145
defp aliases do
146146
[
147147
test: ["sentry.package_source_code", "test"],
148-
"test.integrations": &run_integration_tests_if_supported/1
148+
"test.integrations": &run_integration_tests_if_supported/1,
149+
"test.tracing": ["sentry.tracing.test"],
150+
"tracing.start": ["sentry.tracing.start"],
151+
"tracing.phoenix": ["sentry.tracing.phoenix"],
152+
"tracing.svelte": ["sentry.tracing.svelte"]
149153
]
150154
end
151155

test_integrations/phoenix_app/config/config.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ config :opentelemetry, span_processor: {Sentry.OpenTelemetry.SpanProcessor, []}
6565
config :opentelemetry,
6666
sampler: {Sentry.OpenTelemetry.Sampler, [drop: ["Elixir.Oban.Stager process"]]}
6767

68+
# Configure OpenTelemetry to use Sentry propagator for distributed tracing
69+
config :opentelemetry,
70+
text_map_propagators: [
71+
:trace_context,
72+
:baggage,
73+
Sentry.OpenTelemetry.Propagator
74+
]
75+
6876
# Import environment specific config. This must remain at the bottom
6977
# of this file so it overrides the configuration defined above.
7078
import_config "#{config_env()}.exs"

test_integrations/phoenix_app/config/dev.exs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,19 @@ dsn =
8484
do: System.get_env("SENTRY_DSN_LOCAL"),
8585
else: System.get_env("SENTRY_DSN")
8686

87+
# For e2e tracing tests, use the TestClient to log events to a file
88+
client =
89+
if System.get_env("SENTRY_E2E_TEST_MODE") == "true",
90+
do: PhoenixApp.TestClient,
91+
else: Sentry.HackneyClient
92+
8793
config :sentry,
8894
dsn: dsn,
8995
environment_name: :dev,
9096
enable_source_code_context: true,
9197
send_result: :sync,
92-
traces_sample_rate: 1.0
98+
traces_sample_rate: 1.0,
99+
client: client
93100

94101
config :phoenix_app, Oban,
95102
repo: PhoenixApp.Repo,

test_integrations/phoenix_app/lib/phoenix_app_web/controllers/page_controller.ex

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,37 @@ defmodule PhoenixAppWeb.PageController do
4848

4949
render(conn, :home, layout: false)
5050
end
51+
52+
# E2E tracing test endpoints
53+
def api_error(_conn, _params) do
54+
raise ArithmeticError, "bad argument in arithmetic expression"
55+
end
56+
57+
def health(conn, _params) do
58+
json(conn, %{status: "ok"})
59+
end
60+
61+
def api_data(conn, _params) do
62+
# Fetch actual data from the database
63+
Tracer.with_span "fetch_data" do
64+
users = Repo.all(User)
65+
66+
Tracer.with_span "process_data" do
67+
# Do some processing
68+
user_count = length(users)
69+
70+
# Make another query to demonstrate nested DB operations
71+
first_user = Repo.get(User, 1)
72+
73+
json(conn, %{
74+
message: "Data fetched successfully",
75+
data: %{
76+
user_count: user_count,
77+
first_user: if(first_user, do: first_user.name, else: nil),
78+
timestamp: DateTime.utc_now() |> DateTime.to_iso8601()
79+
}
80+
})
81+
end
82+
end
83+
end
5184
end

test_integrations/phoenix_app/lib/phoenix_app_web/endpoint.ex

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,25 @@ defmodule PhoenixAppWeb.Endpoint do
4444
plug Plug.RequestId
4545
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
4646

47+
# Simple CORS handler for e2e tests
48+
plug :cors
49+
50+
defp cors(conn, _opts) do
51+
conn
52+
|> put_resp_header("access-control-allow-origin", "*")
53+
|> put_resp_header("access-control-allow-methods", "GET, POST, PUT, DELETE, OPTIONS")
54+
|> put_resp_header("access-control-allow-headers", "content-type, sentry-trace, baggage")
55+
|> then(fn conn ->
56+
if conn.method == "OPTIONS" do
57+
conn
58+
|> send_resp(200, "")
59+
|> halt()
60+
else
61+
conn
62+
end
63+
end)
64+
end
65+
4766
plug Plug.Parsers,
4867
parsers: [:urlencoded, :multipart, :json],
4968
pass: ["*/*"],

test_integrations/phoenix_app/lib/phoenix_app_web/router.ex

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ defmodule PhoenixAppWeb.Router do
1212

1313
pipeline :api do
1414
plug :accepts, ["json"]
15+
plug :put_cors_headers
16+
end
17+
18+
defp put_cors_headers(conn, _opts) do
19+
conn
20+
|> put_resp_header("access-control-allow-origin", "*")
21+
|> put_resp_header("access-control-allow-methods", "GET, POST, PUT, DELETE, OPTIONS")
22+
|> put_resp_header("access-control-allow-headers", "content-type, authorization, sentry-trace, baggage")
1523
end
1624

1725
scope "/", PhoenixAppWeb do
@@ -32,6 +40,15 @@ defmodule PhoenixAppWeb.Router do
3240
live "/users/:id/show/edit", UserLive.Show, :edit
3341
end
3442

43+
# API endpoints for e2e tracing tests
44+
scope "/", PhoenixAppWeb do
45+
pipe_through :api
46+
47+
get "/error", PageController, :api_error
48+
get "/health", PageController, :health
49+
get "/api/data", PageController, :api_data
50+
end
51+
3552
# Other scopes may use custom stacks.
3653
# scope "/api", PhoenixAppWeb do
3754
# pipe_through :api

test_integrations/phoenix_app/test/phoenix_app_web/controllers/transaction_test.exs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,29 @@ defmodule Sentry.Integrations.Phoenix.TransactionTest do
129129

130130
refute mount_transaction.contexts.trace.trace_id == handle_params_transaction.contexts.trace.trace_id
131131
end
132+
133+
test "GET /users with distributed tracing headers includes child spans with details", %{conn: conn} do
134+
trace_id = "1234567890abcdef1234567890abcdef"
135+
span_id = "1234567890abcdef"
136+
sentry_trace = "#{trace_id}-#{span_id}-1"
137+
138+
conn = put_req_header(conn, "sentry-trace", sentry_trace)
139+
get(conn, ~p"/users")
140+
141+
transactions = Sentry.Test.pop_sentry_transactions()
142+
143+
assert length(transactions) == 2
144+
145+
assert [mount_transaction, _handle_params_transaction] = transactions
146+
147+
assert mount_transaction.contexts.trace.trace_id == trace_id
148+
assert mount_transaction.contexts.trace.parent_span_id != nil
149+
150+
assert [span_ecto] = mount_transaction.spans
151+
assert span_ecto.op == "db"
152+
153+
assert span_ecto.description == "SELECT u0.\"id\", u0.\"name\", u0.\"age\", u0.\"inserted_at\", u0.\"updated_at\" FROM \"users\" AS u0"
154+
155+
assert span_ecto.data["db.system"] != nil
156+
end
132157
end

0 commit comments

Comments
 (0)