Skip to content

Commit 9278ef6

Browse files
committed
Add custom spans and tracing for GraphQL resolver business logic
- Import OpenTelemetry Tracer module for custom instrumentation - Add resolver.schedule_spacewalk spans for both custom and predefined spacewalks - Include resolver.list_scheduled_walks span for listing operations - Add resolver.delete_spacewalk span for cancellation operations - Set business-specific attributes like spacewalk.type, spacewalk.id, spacewalk.time - Include span status tracking for success/error scenarios - Capture spacewalk count metrics and operation outcomes
1 parent f7113fe commit 9278ef6

File tree

1 file changed

+140
-88
lines changed
  • manual-instrumentation/worms_in_space/lib/worms_in_space_web/api/resolvers

1 file changed

+140
-88
lines changed
Lines changed: 140 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
defmodule Api.Resolvers do
22
alias WormsInSpace.{Repo, ScheduledWalk}
33
import Ecto.Query
4+
require OpenTelemetry.Tracer, as: Tracer
45

56
@time_slots [
67
%{id: 2, start_time: "2020-02-28T16:00:00.000Z"},
@@ -13,109 +14,160 @@ defmodule Api.Resolvers do
1314
end
1415

1516
def list_scheduled_walks(_args, _info) do
16-
walks =
17-
ScheduledWalk
18-
|> where([w], w.status == "scheduled")
19-
|> order_by([w], desc: w.inserted_at)
20-
|> Repo.all()
21-
|> Enum.map(fn walk ->
22-
%{
23-
id: walk.id,
24-
start_time: DateTime.to_iso8601(walk.start_time),
25-
walk_type: walk.walk_type,
26-
slot_id: walk.slot_id,
27-
status: walk.status,
28-
scheduled_at: NaiveDateTime.to_iso8601(walk.inserted_at) <> "Z"
29-
}
30-
end)
31-
32-
{:ok, walks}
17+
Tracer.with_span "resolver.list_scheduled_walks" do
18+
walks =
19+
ScheduledWalk
20+
|> where([w], w.status == "scheduled")
21+
|> order_by([w], desc: w.inserted_at)
22+
|> Repo.all()
23+
|> Enum.map(fn walk ->
24+
%{
25+
id: walk.id,
26+
start_time: DateTime.to_iso8601(walk.start_time),
27+
walk_type: walk.walk_type,
28+
slot_id: walk.slot_id,
29+
status: walk.status,
30+
scheduled_at: NaiveDateTime.to_iso8601(walk.inserted_at) <> "Z"
31+
}
32+
end)
33+
34+
Tracer.set_attributes([
35+
{"spacewalks.count", length(walks)}
36+
])
37+
38+
{:ok, walks}
39+
end
3340
end
3441

3542
def create(%{alternate_time: _alternate_time, id: _id}, _info) do
3643
{:error, %{message: "Bad input.", status: 404}}
3744
end
3845

3946
def create(%{alternate_time: alternate_time}, _info) do
40-
case DateTime.from_iso8601(alternate_time) do
41-
{:ok, datetime, _} ->
42-
changeset = ScheduledWalk.changeset(%ScheduledWalk{}, %{
43-
start_time: datetime,
44-
walk_type: "custom"
45-
})
46-
47-
case Repo.insert(changeset) do
48-
{:ok, walk} ->
49-
{:ok, %{
50-
id: walk.id,
51-
start_time: DateTime.to_iso8601(walk.start_time),
52-
walk_type: walk.walk_type,
53-
slot_id: walk.slot_id,
54-
status: walk.status,
55-
scheduled_at: NaiveDateTime.to_iso8601(walk.inserted_at) <> "Z"
56-
}}
57-
{:error, _changeset} ->
58-
{:error, %{message: "Failed to schedule spacewalk", status: 400}}
59-
end
60-
{:error, _} ->
61-
{:error, %{message: "Invalid datetime format", status: 400}}
47+
Tracer.with_span "resolver.schedule_spacewalk" do
48+
Tracer.set_attributes([
49+
{"spacewalk.type", "custom"},
50+
{"spacewalk.time", alternate_time}
51+
])
52+
53+
case DateTime.from_iso8601(alternate_time) do
54+
{:ok, datetime, _} ->
55+
changeset = ScheduledWalk.changeset(%ScheduledWalk{}, %{
56+
start_time: datetime,
57+
walk_type: "custom"
58+
})
59+
60+
case Repo.insert(changeset) do
61+
{:ok, walk} ->
62+
Tracer.set_attributes([
63+
{"spacewalk.id", walk.id},
64+
{"spacewalk.scheduled", true}
65+
])
66+
Tracer.set_status(:ok)
67+
68+
{:ok, %{
69+
id: walk.id,
70+
start_time: DateTime.to_iso8601(walk.start_time),
71+
walk_type: walk.walk_type,
72+
slot_id: walk.slot_id,
73+
status: walk.status,
74+
scheduled_at: NaiveDateTime.to_iso8601(walk.inserted_at) <> "Z"
75+
}}
76+
{:error, _changeset} ->
77+
Tracer.set_status(:error, "Failed to schedule spacewalk")
78+
{:error, %{message: "Failed to schedule spacewalk", status: 400}}
79+
end
80+
{:error, _} ->
81+
Tracer.set_status(:error, "Invalid datetime format")
82+
{:error, %{message: "Invalid datetime format", status: 400}}
83+
end
6284
end
6385
end
6486

6587
def create(%{id: id}, _info) do
66-
slot = Enum.find(@time_slots, fn %{id: existing_id} ->
67-
existing_id == String.to_integer(id)
68-
end)
69-
70-
case slot do
71-
nil ->
72-
{:error, %{message: "Time slot not found", status: 400}}
73-
slot ->
74-
case DateTime.from_iso8601(slot.start_time) do
75-
{:ok, datetime, _} ->
76-
changeset = ScheduledWalk.changeset(%ScheduledWalk{}, %{
77-
start_time: datetime,
78-
walk_type: "predefined",
79-
slot_id: id
80-
})
81-
82-
case Repo.insert(changeset) do
83-
{:ok, walk} ->
84-
{:ok, %{
85-
id: walk.id,
86-
start_time: DateTime.to_iso8601(walk.start_time),
87-
walk_type: walk.walk_type,
88-
slot_id: walk.slot_id,
89-
status: walk.status,
90-
scheduled_at: NaiveDateTime.to_iso8601(walk.inserted_at) <> "Z"
91-
}}
92-
{:error, _changeset} ->
93-
{:error, %{message: "Failed to schedule spacewalk", status: 400}}
94-
end
95-
{:error, _} ->
96-
{:error, %{message: "Invalid slot datetime", status: 400}}
97-
end
88+
Tracer.with_span "resolver.schedule_spacewalk" do
89+
Tracer.set_attributes([
90+
{"spacewalk.type", "predefined"},
91+
{"timeslot.id", id}
92+
])
93+
94+
slot = Enum.find(@time_slots, fn %{id: existing_id} ->
95+
existing_id == String.to_integer(id)
96+
end)
97+
98+
case slot do
99+
nil ->
100+
Tracer.set_status(:error, "Time slot not found")
101+
{:error, %{message: "Time slot not found", status: 400}}
102+
slot ->
103+
case DateTime.from_iso8601(slot.start_time) do
104+
{:ok, datetime, _} ->
105+
changeset = ScheduledWalk.changeset(%ScheduledWalk{}, %{
106+
start_time: datetime,
107+
walk_type: "predefined",
108+
slot_id: id
109+
})
110+
111+
case Repo.insert(changeset) do
112+
{:ok, walk} ->
113+
Tracer.set_attributes([
114+
{"spacewalk.id", walk.id},
115+
{"spacewalk.scheduled", true}
116+
])
117+
Tracer.set_status(:ok)
118+
119+
{:ok, %{
120+
id: walk.id,
121+
start_time: DateTime.to_iso8601(walk.start_time),
122+
walk_type: walk.walk_type,
123+
slot_id: walk.slot_id,
124+
status: walk.status,
125+
scheduled_at: NaiveDateTime.to_iso8601(walk.inserted_at) <> "Z"
126+
}}
127+
{:error, _changeset} ->
128+
Tracer.set_status(:error, "Failed to schedule spacewalk")
129+
{:error, %{message: "Failed to schedule spacewalk", status: 400}}
130+
end
131+
{:error, _} ->
132+
Tracer.set_status(:error, "Invalid slot datetime")
133+
{:error, %{message: "Invalid slot datetime", status: 400}}
134+
end
135+
end
98136
end
99137
end
100138

101139
def delete_scheduled_walk(%{id: id}, _info) do
102-
case Repo.get(ScheduledWalk, id) do
103-
nil ->
104-
{:error, %{message: "Scheduled walk not found", status: 404}}
105-
walk ->
106-
case Repo.update(ScheduledWalk.changeset(walk, %{status: "cancelled"})) do
107-
{:ok, updated_walk} ->
108-
{:ok, %{
109-
id: updated_walk.id,
110-
start_time: DateTime.to_iso8601(updated_walk.start_time),
111-
walk_type: updated_walk.walk_type,
112-
slot_id: updated_walk.slot_id,
113-
status: updated_walk.status,
114-
scheduled_at: NaiveDateTime.to_iso8601(updated_walk.inserted_at) <> "Z"
115-
}}
116-
{:error, _changeset} ->
117-
{:error, %{message: "Failed to cancel spacewalk", status: 400}}
118-
end
140+
Tracer.with_span "resolver.delete_spacewalk" do
141+
Tracer.set_attributes([
142+
{"spacewalk.id", id}
143+
])
144+
145+
case Repo.get(ScheduledWalk, id) do
146+
nil ->
147+
Tracer.set_status(:error, "Scheduled walk not found")
148+
{:error, %{message: "Scheduled walk not found", status: 404}}
149+
walk ->
150+
case Repo.update(ScheduledWalk.changeset(walk, %{status: "cancelled"})) do
151+
{:ok, updated_walk} ->
152+
Tracer.set_attributes([
153+
{"spacewalk.cancelled", true},
154+
{"spacewalk.walk_type", updated_walk.walk_type}
155+
])
156+
Tracer.set_status(:ok)
157+
158+
{:ok, %{
159+
id: updated_walk.id,
160+
start_time: DateTime.to_iso8601(updated_walk.start_time),
161+
walk_type: updated_walk.walk_type,
162+
slot_id: updated_walk.slot_id,
163+
status: updated_walk.status,
164+
scheduled_at: NaiveDateTime.to_iso8601(updated_walk.inserted_at) <> "Z"
165+
}}
166+
{:error, _changeset} ->
167+
Tracer.set_status(:error, "Failed to cancel spacewalk")
168+
{:error, %{message: "Failed to cancel spacewalk", status: 400}}
169+
end
170+
end
119171
end
120172
end
121173
end

0 commit comments

Comments
 (0)