Skip to content

Commit d5c4b44

Browse files
committed
Introduce SpanRecord to simplify processing
1 parent a86dd39 commit d5c4b44

File tree

2 files changed

+120
-105
lines changed

2 files changed

+120
-105
lines changed

lib/sentry/opentelemetry/span_processor.ex

Lines changed: 113 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,43 @@
11
defmodule Sentry.Opentelemetry.SpanProcessor do
22
@behaviour :otel_span_processor
33

4-
require Record
4+
alias Sentry.{Span, Transaction, Opentelemetry.SpanStorage}
55

6-
@fields Record.extract(:span, from: "deps/opentelemetry/include/otel_span.hrl")
7-
Record.defrecordp(:span, @fields)
6+
defmodule SpanRecord do
7+
require Record
88

9-
alias Sentry.{Span, Transaction, Opentelemetry.SpanStorage}
9+
@fields Record.extract(:span, from: "deps/opentelemetry/include/otel_span.hrl")
10+
Record.defrecordp(:span, @fields)
11+
12+
defstruct @fields ++ [:origin]
13+
14+
def new(otel_span) do
15+
otel_attrs = span(otel_span)
16+
17+
{:attributes, _, _, _, attributes} = otel_attrs[:attributes]
18+
19+
origin =
20+
case otel_attrs[:instrumentation_scope] do
21+
{:instrumentation_scope, origin, _version, _} ->
22+
origin
23+
24+
_ ->
25+
:undefined
26+
end
27+
28+
attrs =
29+
otel_attrs
30+
|> Keyword.delete(:attributes)
31+
|> Keyword.merge(origin: origin, attributes: attributes)
32+
|> Map.new()
33+
34+
struct(__MODULE__, attrs)
35+
end
36+
end
1037

1138
@impl true
1239
def on_start(_ctx, otel_span, _config) do
13-
span_record = span(otel_span)
40+
span_record = SpanRecord.new(otel_span)
1441

1542
SpanStorage.store_span(span_record)
1643

@@ -19,13 +46,13 @@ defmodule Sentry.Opentelemetry.SpanProcessor do
1946

2047
@impl true
2148
def on_end(otel_span, _config) do
22-
span_record = span(otel_span)
49+
span_record = SpanRecord.new(otel_span)
2350

2451
SpanStorage.update_span(span_record)
2552

26-
if span_record[:parent_span_id] == :undefined do
27-
root_span = SpanStorage.get_root_span(span_record[:span_id])
28-
child_spans = SpanStorage.get_child_spans(span_record[:span_id])
53+
if span_record.parent_span_id == :undefined do
54+
root_span = SpanStorage.get_root_span(span_record.span_id)
55+
child_spans = SpanStorage.get_child_spans(span_record.span_id)
2956

3057
transaction = transaction_from_root_span(root_span, child_spans)
3158
Sentry.send_transaction(transaction)
@@ -40,60 +67,46 @@ defmodule Sentry.Opentelemetry.SpanProcessor do
4067
end
4168

4269
defp transaction_from_root_span(root_span, child_spans) do
43-
{:attributes, _, _, _, attributes} = root_span[:attributes]
44-
45-
build_transaction(attributes, root_span, child_spans)
46-
end
47-
48-
defp build_transaction(attributes, root_span, child_spans) when is_map(attributes) do
49-
trace_id = cast_trace_id(root_span[:trace_id])
50-
51-
case root_span[:instrumentation_scope] do
52-
{:instrumentation_scope, origin, _version, _} ->
53-
build_transaction(origin, trace_id, root_span, child_spans, attributes)
70+
trace_id = cast_trace_id(root_span.trace_id)
5471

55-
:undefined ->
56-
build_transaction(trace_id, root_span, child_spans)
57-
end
72+
build_transaction(trace_id, root_span, child_spans)
5873
end
5974

60-
defp build_transaction(trace_id, root_span, child_spans) when is_binary(trace_id) do
75+
defp build_transaction(trace_id, %SpanRecord{origin: :undefined} = root_span, child_spans) do
6176
Transaction.new(%{
62-
transaction: root_span[:name],
63-
start_timestamp: cast_timestamp(root_span[:start_time]),
64-
timestamp: cast_timestamp(root_span[:end_time]),
77+
transaction: root_span.name,
78+
start_timestamp: cast_timestamp(root_span.start_time),
79+
timestamp: cast_timestamp(root_span.end_time),
6580
contexts: %{
6681
trace: %{
6782
trace_id: trace_id,
68-
span_id: cast_span_id(root_span[:span_id]),
69-
op: root_span[:name]
83+
span_id: cast_span_id(root_span.span_id),
84+
op: root_span.name
7085
}
7186
},
7287
spans: Enum.map([root_span | child_spans], &build_span(&1, trace_id))
7388
})
7489
end
7590

7691
defp build_transaction(
77-
"opentelemetry_ecto" = origin,
7892
trace_id,
79-
root_span,
80-
child_spans,
81-
attributes
93+
%SpanRecord{attributes: attributes, origin: "opentelemetry_ecto"} = root_span,
94+
child_spans
8295
) do
8396
Transaction.new(%{
84-
transaction: root_span[:name],
85-
start_timestamp: cast_timestamp(root_span[:start_time]),
86-
timestamp: cast_timestamp(root_span[:end_time]),
97+
transaction: root_span.name,
98+
start_timestamp: cast_timestamp(root_span.start_time),
99+
timestamp: cast_timestamp(root_span.end_time),
87100
transaction_info: %{
88101
source: "db"
89102
},
90103
contexts: %{
91104
trace: %{
92105
trace_id: trace_id,
93-
span_id: cast_span_id(root_span[:span_id]),
94-
parent_span_id: cast_span_id(root_span[:parent_span_id]),
106+
span_id: cast_span_id(root_span.span_id),
107+
parent_span_id: cast_span_id(root_span.parent_span_id),
95108
op: "db",
96-
origin: origin
109+
origin: root_span.origin
97110
}
98111
},
99112
platform: "elixir",
@@ -119,19 +132,17 @@ defmodule Sentry.Opentelemetry.SpanProcessor do
119132
end
120133

121134
defp build_transaction(
122-
"opentelemetry_phoenix" = origin,
123135
trace_id,
124-
root_span,
125-
child_spans,
126-
attributes
136+
%SpanRecord{attributes: attributes, origin: "opentelemetry_phoenix"} = root_span,
137+
child_spans
127138
) do
128139
name = "#{attributes[:"phoenix.plug"]}##{attributes[:"phoenix.action"]}"
129-
trace = build_trace_context(trace_id, origin, root_span, attributes)
140+
trace = build_trace_context(trace_id, root_span)
130141

131142
Transaction.new(%{
132143
transaction: name,
133-
start_timestamp: cast_timestamp(root_span[:start_time]),
134-
timestamp: cast_timestamp(root_span[:end_time]),
144+
start_timestamp: cast_timestamp(root_span.start_time),
145+
timestamp: cast_timestamp(root_span.end_time),
135146
transaction_info: %{
136147
source: "view"
137148
},
@@ -168,20 +179,24 @@ defmodule Sentry.Opentelemetry.SpanProcessor do
168179
})
169180
end
170181

171-
defp build_transaction("opentelemetry_bandit", trace_id, root_span, child_spans, attributes) do
182+
defp build_transaction(
183+
trace_id,
184+
%SpanRecord{attributes: attributes, origin: "opentelemetry_bandit"} = root_span,
185+
child_spans
186+
) do
172187
%Sentry.Transaction{
173188
event_id: Sentry.UUID.uuid4_hex(),
174-
start_timestamp: cast_timestamp(root_span[:start_time]),
175-
timestamp: cast_timestamp(root_span[:end_time]),
189+
start_timestamp: cast_timestamp(root_span.start_time),
190+
timestamp: cast_timestamp(root_span.end_time),
176191
transaction: attributes[:"http.target"],
177192
transaction_info: %{
178193
source: "url"
179194
},
180195
contexts: %{
181196
trace: %{
182197
trace_id: trace_id,
183-
span_id: cast_span_id(root_span[:span_id]),
184-
parent_span_id: cast_span_id(root_span[:parent_span_id])
198+
span_id: cast_span_id(root_span.span_id),
199+
parent_span_id: cast_span_id(root_span.parent_span_id)
185200
}
186201
},
187202
platform: "elixir",
@@ -205,10 +220,13 @@ defmodule Sentry.Opentelemetry.SpanProcessor do
205220
}
206221
end
207222

208-
defp build_trace_context(trace_id, origin, root_span, attributes) do
223+
defp build_trace_context(
224+
trace_id,
225+
%SpanRecord{origin: origin, attributes: attributes} = root_span
226+
) do
209227
%{
210228
trace_id: trace_id,
211-
span_id: cast_span_id(root_span[:span_id]),
229+
span_id: cast_span_id(root_span.span_id),
212230
parent_span_id: nil,
213231
op: "http.server",
214232
origin: origin,
@@ -218,81 +236,78 @@ defmodule Sentry.Opentelemetry.SpanProcessor do
218236
}
219237
end
220238

221-
defp build_span(span_record, trace_id) do
222-
{:attributes, _, _, _, attributes} = span_record[:attributes]
223-
224-
case span_record[:instrumentation_scope] do
225-
{:instrumentation_scope, origin, _version, _} ->
226-
build_span(origin, span_record, trace_id, attributes)
227-
228-
:undefined ->
229-
build_span(:custom, span_record, trace_id, attributes)
230-
end
231-
end
232-
233-
defp build_span("opentelemetry_phoenix" = origin, span_record, trace_id, attributes) do
239+
defp build_span(
240+
%SpanRecord{origin: "opentelemetry_phoenix", attributes: attributes} = span_record,
241+
trace_id
242+
) do
234243
op = "#{attributes[:"phoenix.plug"]}##{attributes[:"phoenix.action"]}"
235244

236245
%Span{
237246
op: op,
238-
start_timestamp: cast_timestamp(span_record[:start_time]),
239-
timestamp: cast_timestamp(span_record[:end_time]),
247+
start_timestamp: cast_timestamp(span_record.start_time),
248+
timestamp: cast_timestamp(span_record.end_time),
240249
trace_id: trace_id,
241-
span_id: cast_span_id(span_record[:span_id]),
242-
parent_span_id: cast_span_id(span_record[:parent_span_id]),
250+
span_id: cast_span_id(span_record.span_id),
251+
parent_span_id: cast_span_id(span_record.parent_span_id),
243252
description: attributes[:"http.route"],
244-
origin: origin
253+
origin: span_record.origin
245254
}
246255
end
247256

248-
defp build_span("phoenix_app", span_record, trace_id, _attributes) do
257+
defp build_span(%SpanRecord{origin: "phoenix_app"} = span_record, trace_id) do
249258
%Span{
250259
trace_id: trace_id,
251-
op: span_record[:name],
252-
start_timestamp: cast_timestamp(span_record[:start_time]),
253-
timestamp: cast_timestamp(span_record[:end_time]),
254-
span_id: cast_span_id(span_record[:span_id]),
255-
parent_span_id: cast_span_id(span_record[:parent_span_id])
260+
op: span_record.name,
261+
start_timestamp: cast_timestamp(span_record.start_time),
262+
timestamp: cast_timestamp(span_record.end_time),
263+
span_id: cast_span_id(span_record.span_id),
264+
parent_span_id: cast_span_id(span_record.parent_span_id)
256265
}
257266
end
258267

259-
defp build_span("opentelemetry_bandit" = origin, span_record, trace_id, _attributes) do
268+
defp build_span(%SpanRecord{origin: "opentelemetry_bandit"} = span_record, trace_id) do
260269
%Span{
261270
trace_id: trace_id,
262-
op: span_record[:name],
263-
start_timestamp: cast_timestamp(span_record[:start_time]),
264-
timestamp: cast_timestamp(span_record[:end_time]),
265-
span_id: cast_span_id(span_record[:span_id]),
266-
parent_span_id: cast_span_id(span_record[:parent_span_id]),
267-
description: span_record[:name],
268-
origin: origin
271+
op: span_record.name,
272+
start_timestamp: cast_timestamp(span_record.start_time),
273+
timestamp: cast_timestamp(span_record.end_time),
274+
span_id: cast_span_id(span_record.span_id),
275+
parent_span_id: cast_span_id(span_record.parent_span_id),
276+
description: span_record.name,
277+
origin: span_record.origin
269278
}
270279
end
271280

272-
defp build_span("opentelemetry_ecto" = origin, span_record, trace_id, attributes) do
281+
defp build_span(
282+
%SpanRecord{origin: "opentelemetry_ecto", attributes: attributes} = span_record,
283+
trace_id
284+
) do
273285
%Span{
274286
trace_id: trace_id,
275-
op: span_record[:name],
276-
start_timestamp: cast_timestamp(span_record[:start_time]),
277-
timestamp: cast_timestamp(span_record[:end_time]),
278-
span_id: cast_span_id(span_record[:span_id]),
279-
parent_span_id: cast_span_id(span_record[:parent_span_id]),
280-
origin: origin,
287+
op: span_record.name,
288+
start_timestamp: cast_timestamp(span_record.start_time),
289+
timestamp: cast_timestamp(span_record.end_time),
290+
span_id: cast_span_id(span_record.span_id),
291+
parent_span_id: cast_span_id(span_record.parent_span_id),
292+
origin: span_record.origin,
281293
data: %{
282294
"db.system" => attributes[:"db.system"],
283295
"db.name" => attributes[:"db.name"]
284296
}
285297
}
286298
end
287299

288-
defp build_span(:custom, span_record, trace_id, _attributes) do
300+
defp build_span(
301+
%SpanRecord{origin: :undefined, attributes: _attributes} = span_record,
302+
trace_id
303+
) do
289304
%Span{
290305
trace_id: trace_id,
291-
op: span_record[:name],
292-
start_timestamp: cast_timestamp(span_record[:start_time]),
293-
timestamp: cast_timestamp(span_record[:end_time]),
294-
span_id: cast_span_id(span_record[:span_id]),
295-
parent_span_id: cast_span_id(span_record[:parent_span_id])
306+
op: span_record.name,
307+
start_timestamp: cast_timestamp(span_record.start_time),
308+
timestamp: cast_timestamp(span_record.end_time),
309+
span_id: cast_span_id(span_record.span_id),
310+
parent_span_id: cast_span_id(span_record.parent_span_id)
296311
}
297312
end
298313

lib/sentry/opentelemetry/span_storage.ex

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ defmodule Sentry.Opentelemetry.SpanStorage do
2626
end
2727

2828
def handle_call({:store_span, span_data}, _from, state) do
29-
if span_data[:parent_span_id] == :undefined do
30-
new_state = put_in(state, [:root_spans, span_data[:span_id]], span_data)
29+
if span_data.parent_span_id == :undefined do
30+
new_state = put_in(state, [:root_spans, span_data.span_id], span_data)
3131
{:reply, :ok, new_state}
3232
else
3333
new_state =
34-
update_in(state, [:child_spans, span_data[:parent_span_id]], fn spans ->
34+
update_in(state, [:child_spans, span_data.parent_span_id], fn spans ->
3535
(spans || []) ++ [span_data]
3636
end)
3737

@@ -48,14 +48,14 @@ defmodule Sentry.Opentelemetry.SpanStorage do
4848
end
4949

5050
def handle_call({:update_span, span_data}, _from, state) do
51-
if span_data[:parent_span_id] == :undefined do
52-
new_state = put_in(state, [:root_spans, span_data[:span_id]], span_data)
51+
if span_data.parent_span_id == :undefined do
52+
new_state = put_in(state, [:root_spans, span_data.span_id], span_data)
5353
{:reply, :ok, new_state}
5454
else
5555
new_state =
56-
update_in(state, [:child_spans, span_data[:parent_span_id]], fn spans ->
56+
update_in(state, [:child_spans, span_data.parent_span_id], fn spans ->
5757
Enum.map(spans || [], fn span ->
58-
if span[:span_id] == span_data[:span_id], do: span_data, else: span
58+
if span.span_id == span_data.span_id, do: span_data, else: span
5959
end)
6060
end)
6161

0 commit comments

Comments
 (0)