Fix two use cases of Ecto span propagation (#82)
First one is related to `OpenTelemetry.Ctx` API. I've noticed in a few scenarios the current span of a trace may get lost after Ecto calls. Looking at the The `attach/1` typespec, it's a Ctx -> Token, while `dettach/1` as Token -> Ctx function. That made me assume the expected input of dettach is the return type of attach. Indeed, after this change we got the behavior of Ecto calls preserve the parent span untouched. That leads to a second bug found. When ecto does simple calls within a Task, due the special propagation code for preloads that means it will skip the current span, if any. The solution here is to first check the current process. One test was added to reproduce this bug.
This commit is contained in:
parent
4d39f47b03
commit
56c6503a93
|
@ -108,10 +108,20 @@ defmodule OpentelemetryEcto do
|
|||
|> Map.merge(base_attributes)
|
||||
|> Map.merge(additional_attributes)
|
||||
|
||||
parent_context = OpentelemetryProcessPropagator.fetch_parent_ctx(1, :"$callers")
|
||||
parent_context =
|
||||
case OpentelemetryProcessPropagator.fetch_ctx(self()) do
|
||||
:undefined ->
|
||||
OpentelemetryProcessPropagator.fetch_parent_ctx(1, :"$callers")
|
||||
|
||||
ctx ->
|
||||
ctx
|
||||
end
|
||||
|
||||
parent_token =
|
||||
if parent_context != :undefined do
|
||||
OpenTelemetry.Ctx.attach(parent_context)
|
||||
else
|
||||
:undefined
|
||||
end
|
||||
|
||||
s =
|
||||
|
@ -131,8 +141,8 @@ defmodule OpentelemetryEcto do
|
|||
|
||||
OpenTelemetry.Span.end_span(s)
|
||||
|
||||
if parent_context != :undefined do
|
||||
OpenTelemetry.Ctx.detach(parent_context)
|
||||
if parent_token != :undefined do
|
||||
OpenTelemetry.Ctx.detach(parent_token)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -192,6 +192,29 @@ defmodule OpentelemetryEctoTest do
|
|||
assert_receive {:span, span(parent_span_id: ^root_span_id, name: "opentelemetry_ecto.test_repo.query:comments")}
|
||||
end
|
||||
|
||||
test "nested query within Task does not skip parent span" do
|
||||
user = Repo.insert!(%User{email: "opentelemetry@erlang.org"})
|
||||
Repo.insert!(%Post{body: "We got traced!", user: user})
|
||||
Repo.insert!(%Comment{body: "We got traced!", user: user})
|
||||
|
||||
attach_handler()
|
||||
|
||||
Tracer.with_span "root span" do
|
||||
task =
|
||||
Task.async(fn ->
|
||||
Tracer.with_span "parent span" do
|
||||
Repo.all(User)
|
||||
end
|
||||
end)
|
||||
|
||||
Task.await(task)
|
||||
end
|
||||
|
||||
assert_receive {:span, span(span_id: _root_span_id, name: "root span")}
|
||||
assert_receive {:span, span(span_id: parent_span_id, name: "parent span")}
|
||||
assert_receive {:span, span(parent_span_id: ^parent_span_id, name: "opentelemetry_ecto.test_repo.query:users")}
|
||||
end
|
||||
|
||||
def attach_handler(config \\ []) do
|
||||
# For now setup the handler manually in each test
|
||||
handler = {__MODULE__, self()}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
OpentelemetryEcto.TestRepo.start_link()
|
||||
|
||||
ExUnit.start()
|
||||
ExUnit.start(capture_log: true)
|
||||
|
||||
Ecto.Adapters.SQL.Sandbox.mode(OpentelemetryEcto.TestRepo, {:shared, self()})
|
||||
|
|
Loading…
Reference in New Issue