Skip to content

Commit 96c8748

Browse files
committed
Make root span the transaction
1 parent d6b9524 commit 96c8748

File tree

7 files changed

+100
-84
lines changed

7 files changed

+100
-84
lines changed

lib/sentry/opentelemetry/span_processor.ex

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ defmodule Sentry.OpenTelemetry.SpanProcessor do
5757
defp build_transaction(%SpanRecord{origin: :undefined} = root_span, child_spans) do
5858
Transaction.new(%{
5959
transaction: root_span.name,
60-
start_timestamp: root_span.start_time,
61-
timestamp: root_span.end_time,
60+
span_id: root_span.span_id,
6261
contexts: %{
6362
trace: build_trace_context(root_span)
6463
},
@@ -69,8 +68,7 @@ defmodule Sentry.OpenTelemetry.SpanProcessor do
6968
defp build_transaction(%SpanRecord{origin: "opentelemetry_ecto"} = root_span, child_spans) do
7069
Transaction.new(%{
7170
transaction: root_span.name,
72-
start_timestamp: root_span.start_time,
73-
timestamp: root_span.end_time,
71+
span_id: root_span.span_id,
7472
transaction_info: %{
7573
source: "component"
7674
},
@@ -90,8 +88,7 @@ defmodule Sentry.OpenTelemetry.SpanProcessor do
9088
when map_size(attributes) > 0 do
9189
Transaction.new(%{
9290
transaction: "#{attributes["phoenix.plug"]}##{attributes["phoenix.action"]}",
93-
start_timestamp: root_span.start_time,
94-
timestamp: root_span.end_time,
91+
span_id: root_span.span_id,
9592
transaction_info: %{
9693
source: "view"
9794
},
@@ -130,8 +127,7 @@ defmodule Sentry.OpenTelemetry.SpanProcessor do
130127
when map_size(attributes) == 0 do
131128
Transaction.new(%{
132129
transaction: root_span.name,
133-
start_timestamp: root_span.start_time,
134-
timestamp: root_span.end_time,
130+
span_id: root_span.span_id,
135131
transaction_info: %{
136132
source: "view"
137133
},
@@ -147,8 +143,7 @@ defmodule Sentry.OpenTelemetry.SpanProcessor do
147143
child_spans
148144
) do
149145
Transaction.new(%{
150-
start_timestamp: root_span.start_time,
151-
timestamp: root_span.end_time,
146+
span_id: root_span.span_id,
152147
transaction: attributes["http.target"],
153148
transaction_info: %{
154149
source: "url"
@@ -175,8 +170,7 @@ defmodule Sentry.OpenTelemetry.SpanProcessor do
175170
defp build_transaction(%SpanRecord{origin: "opentelemetry_oban"} = root_span, child_spans) do
176171
Transaction.new(%{
177172
transaction: root_span.name |> String.split(" ") |> List.first(),
178-
start_timestamp: root_span.start_time,
179-
timestamp: root_span.end_time,
173+
span_id: root_span.span_id,
180174
transaction_info: %{
181175
source: "task"
182176
},

lib/sentry/test.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ defmodule Sentry.Test do
361361
362362
iex> Sentry.Test.start_collecting_sentry_reports()
363363
:ok
364-
iex> Sentry.send_transaction(%Sentry.Transaction{})
364+
iex> Sentry.send_transaction(Sentry.Transaction.new(%{span_id: "123", spans: []}))
365365
{:ok, ""}
366366
iex> [%Sentry.Transaction{}] = Sentry.Test.pop_sentry_transactions()
367367

lib/sentry/transaction.ex

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,24 @@ defmodule Sentry.Transaction do
33

44
alias Sentry.{Config, UUID}
55

6+
@enforce_keys ~w(event_id span_id spans)a
7+
68
defstruct [
79
:event_id,
810
:environment,
9-
:start_timestamp,
10-
:timestamp,
11+
:span_id,
1112
:transaction,
1213
:transaction_info,
13-
:status,
1414
:contexts,
1515
:request,
16+
:data,
1617
:measurements,
17-
spans: [],
18+
:spans,
1819
type: "transaction"
1920
]
2021

2122
def new(attrs) do
22-
struct(
23+
struct!(
2324
__MODULE__,
2425
attrs
2526
|> Map.put(:event_id, UUID.uuid4_hex())
@@ -30,27 +31,32 @@ defmodule Sentry.Transaction do
3031
# Used to then encode the returned map to JSON.
3132
@doc false
3233
def to_map(%__MODULE__{} = transaction) do
33-
Map.put(
34-
Map.from_struct(transaction),
35-
:spans,
36-
Enum.map(transaction.spans, &Sentry.Span.to_map(&1))
37-
)
34+
transaction_attrs = Map.take(transaction, [:event_id, :environment, :transaction, :transaction_info, :contexts, :measurements, :type])
35+
{[root_span], child_spans} = Enum.split_with(transaction.spans, &is_nil(&1.parent_span_id))
36+
37+
root_span
38+
|> Sentry.Span.to_map()
39+
|> Map.put(:spans, Enum.map(child_spans, &Sentry.Span.to_map/1))
40+
|> Map.drop([:description])
41+
|> Map.merge(transaction_attrs)
3842
end
3943
end
4044

4145
defmodule Sentry.Span do
46+
@enforce_keys ~w(span_id trace_id start_timestamp timestamp)a
47+
4248
defstruct [
43-
:op,
49+
:trace_id,
50+
:span_id,
51+
:parent_span_id,
4452
:start_timestamp,
4553
:timestamp,
4654
:description,
47-
:span_id,
48-
:parent_span_id,
49-
:trace_id,
55+
:op,
56+
:status,
5057
:tags,
5158
:data,
52-
:origin,
53-
:status
59+
:origin
5460
]
5561

5662
# Used to then encode the returned map to JSON.

test/envelope_test.exs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ defmodule Sentry.EnvelopeTest do
117117
test "works with transactions" do
118118
put_test_config(environment_name: "test")
119119

120-
spans = [
120+
root_span =
121121
%Sentry.Span{
122122
start_timestamp: 1_588_601_261.481_961,
123123
timestamp: 1_588_601_261.488_901,
124124
description: "GET /sockjs-node/info",
125125
op: "http",
126126
span_id: "b01b9f6349558cd1",
127-
parent_span_id: "b0e6f15b45c36b12",
127+
parent_span_id: nil,
128128
trace_id: "1e57b752bc6e4544bbaa246cd1d05dee",
129129
tags: %{"http.status_code" => "200"},
130130
data: %{
@@ -133,23 +133,27 @@ defmodule Sentry.EnvelopeTest do
133133
"type" => "xhr",
134134
"method" => "GET"
135135
}
136-
},
137-
%Sentry.Span{
138-
start_timestamp: 1_588_601_261.535_386,
139-
timestamp: 1_588_601_261.544_196,
140-
description: "Vue <App>",
141-
op: "update",
142-
span_id: "b980d4dec78d7344",
143-
parent_span_id: "9312d0d18bf51736",
144-
trace_id: "1e57b752bc6e4544bbaa246cd1d05dee"
145136
}
146-
]
147137

148-
transaction = %Sentry.Transaction{
149-
start_timestamp: System.system_time(:second),
150-
timestamp: System.system_time(:second),
151-
spans: spans
152-
}
138+
child_spans =
139+
[
140+
%Sentry.Span{
141+
start_timestamp: 1_588_601_261.535_386,
142+
timestamp: 1_588_601_261.544_196,
143+
description: "Vue <App>",
144+
op: "update",
145+
span_id: "b980d4dec78d7344",
146+
parent_span_id: "9312d0d18bf51736",
147+
trace_id: "1e57b752bc6e4544bbaa246cd1d05dee"
148+
}
149+
]
150+
151+
transaction =
152+
Sentry.Transaction.new(%{
153+
span_id: root_span.span_id,
154+
spans: [root_span | child_spans],
155+
transaction: "test-transaction"
156+
})
153157

154158
envelope = Envelope.from_transaction(transaction)
155159

@@ -159,16 +163,13 @@ defmodule Sentry.EnvelopeTest do
159163

160164
assert {:ok, decoded_transaction} = Jason.decode(transaction_line)
161165
assert decoded_transaction["type"] == "transaction"
162-
assert decoded_transaction["start_timestamp"] == transaction.start_timestamp
163-
assert decoded_transaction["timestamp"] == transaction.timestamp
164-
165-
assert [span1, span2] = decoded_transaction["spans"]
166+
assert decoded_transaction["start_timestamp"] == root_span.start_timestamp
167+
assert decoded_transaction["timestamp"] == root_span.timestamp
166168

167-
assert span1["start_timestamp"] == List.first(spans).start_timestamp
168-
assert span1["timestamp"] == List.first(spans).timestamp
169+
assert [span] = decoded_transaction["spans"]
169170

170-
assert span2["start_timestamp"] == List.last(spans).start_timestamp
171-
assert span2["timestamp"] == List.last(spans).timestamp
171+
assert span["start_timestamp"] == List.first(child_spans).start_timestamp
172+
assert span["timestamp"] == List.first(child_spans).timestamp
172173
end
173174
end
174175

test/sentry/client_report/sender_test.exs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule Sentry.ClientReportTest do
44
import Sentry.TestHelpers
55

66
alias Sentry.ClientReport.Sender
7-
alias Sentry.{Event, Transaction}
7+
alias Sentry.{Event, Transaction, Span}
88

99
setup do
1010
original_retries =
@@ -19,6 +19,8 @@ defmodule Sentry.ClientReportTest do
1919
%{bypass: bypass}
2020
end
2121

22+
@span_id Sentry.UUID.uuid4_hex()
23+
2224
describe "record_discarded_events/2 + flushing" do
2325
test "succefully records the discarded event to the client report", %{bypass: bypass} do
2426
start_supervised!({Sender, name: :test_client_report})
@@ -28,10 +30,16 @@ defmodule Sentry.ClientReportTest do
2830
event_id: Sentry.UUID.uuid4_hex(),
2931
timestamp: "2024-10-12T13:21:13"
3032
},
31-
%Transaction{
32-
event_id: Sentry.UUID.uuid4_hex(),
33-
timestamp: "2024-10-12T13:21:13"
34-
}
33+
Transaction.new(%{
34+
span_id: @span_id,
35+
transaction: "test-transaction",
36+
spans: [%Span{
37+
span_id: @span_id,
38+
trace_id: Sentry.UUID.uuid4_hex(),
39+
start_timestamp: "2024-10-12T13:21:13",
40+
timestamp: "2024-10-12T13:21:13"
41+
}]
42+
})
3543
]
3644

3745
assert :ok = Sender.record_discarded_events(:before_send, events, :test_client_report)

test/sentry/opentelemetry/span_processor_test.exs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,17 @@ defmodule Sentry.Opentelemetry.SpanProcessorTest do
4444

4545
assert [%Sentry.Transaction{} = transaction] = Sentry.Test.pop_sentry_transactions()
4646

47-
assert transaction.environment == "test"
48-
assert transaction.type == "transaction"
49-
assert_valid_iso8601(transaction.timestamp)
50-
assert_valid_iso8601(transaction.start_timestamp)
51-
assert transaction.timestamp > transaction.start_timestamp
52-
assert length(transaction.spans) == 1
53-
54-
assert_valid_trace_id(transaction.contexts.trace.trace_id)
55-
56-
assert [span] = transaction.spans
57-
58-
assert span.op == "child_instrumented_function_one"
47+
transaction_data = Sentry.Transaction.to_map(transaction)
48+
49+
assert transaction_data.event_id
50+
assert transaction_data.environment == "test"
51+
assert transaction_data.type == "transaction"
52+
assert transaction_data.op == "child_instrumented_function_one"
53+
assert_valid_iso8601(transaction_data.timestamp)
54+
assert_valid_iso8601(transaction_data.start_timestamp)
55+
assert transaction_data.timestamp > transaction_data.start_timestamp
56+
assert_valid_trace_id(transaction_data.contexts.trace.trace_id)
57+
assert length(transaction_data.spans) == 0
5958
end
6059

6160
test "sends captured spans as transactions with child spans" do
@@ -67,14 +66,15 @@ defmodule Sentry.Opentelemetry.SpanProcessorTest do
6766

6867
assert [%Sentry.Transaction{} = transaction] = Sentry.Test.pop_sentry_transactions()
6968

70-
assert transaction.environment == "test"
71-
assert transaction.type == "transaction"
72-
assert_valid_iso8601(transaction.timestamp)
73-
assert_valid_iso8601(transaction.start_timestamp)
74-
assert transaction.timestamp > transaction.start_timestamp
75-
assert length(transaction.spans) == 3
69+
transaction_data = Sentry.Transaction.to_map(transaction)
70+
71+
assert transaction_data.op == "instrumented_function"
72+
assert_valid_iso8601(transaction_data.timestamp)
73+
assert_valid_iso8601(transaction_data.start_timestamp)
74+
assert transaction_data.timestamp > transaction_data.start_timestamp
75+
assert length(transaction_data.spans) == 2
7676

77-
[root_span, child_span_one, child_span_two] = transaction.spans
77+
[child_span_one, child_span_two] = transaction_data.spans
7878
assert child_span_one.op == "child_instrumented_function_one"
7979
assert child_span_two.op == "child_instrumented_function_two"
8080
assert child_span_one.parent_span_id == transaction.contexts.trace.span_id
@@ -87,10 +87,10 @@ defmodule Sentry.Opentelemetry.SpanProcessorTest do
8787

8888
assert child_span_one.timestamp > child_span_one.start_timestamp
8989
assert child_span_two.timestamp > child_span_two.start_timestamp
90-
assert root_span.timestamp >= child_span_one.timestamp
91-
assert root_span.timestamp >= child_span_two.timestamp
92-
assert root_span.start_timestamp <= child_span_one.start_timestamp
93-
assert root_span.start_timestamp <= child_span_two.start_timestamp
90+
assert transaction_data.timestamp >= child_span_one.timestamp
91+
assert transaction_data.timestamp >= child_span_two.timestamp
92+
assert transaction_data.start_timestamp <= child_span_one.start_timestamp
93+
assert transaction_data.start_timestamp <= child_span_two.start_timestamp
9494

9595
assert_valid_trace_id(transaction.contexts.trace.trace_id)
9696
assert_valid_trace_id(child_span_one.trace_id)

test/sentry_test.exs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,16 @@ defmodule SentryTest do
240240
setup do
241241
transaction =
242242
Sentry.Transaction.new(%{
243+
span_id: "root-span",
243244
transaction: "test-transaction",
244-
start_timestamp: System.system_time(:second),
245-
timestamp: System.system_time(:second)
245+
spans: [
246+
%Sentry.Span{
247+
span_id: "root-span",
248+
trace_id: "trace-id",
249+
start_timestamp: 1_234_567_891.123_456,
250+
timestamp: 1_234_567_891.123_456
251+
}
252+
]
246253
})
247254

248255
{:ok, transaction: transaction}

0 commit comments

Comments
 (0)