Skip to content

Commit ef59c6f

Browse files
committed
WIP - refine Transaction
1 parent b82f55c commit ef59c6f

10 files changed

Lines changed: 139 additions & 65 deletions

File tree

lib/sentry/client.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ defmodule Sentry.Client do
285285
@spec render_transaction(%Transaction{}) :: map()
286286
def render_transaction(%Transaction{} = transaction) do
287287
transaction
288-
|> Transaction.to_map()
288+
|> Transaction.to_payload()
289289
|> Map.merge(%{
290290
platform: "elixir",
291291
sdk: %{

lib/sentry/envelope.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ defmodule Sentry.Envelope do
157157
end
158158

159159
defp item_to_binary(json_library, %Transaction{} = transaction) do
160-
case transaction |> Sentry.Client.render_transaction() |> json_library.encode() do
160+
case transaction |> Sentry.Client.render_transaction() |> Sentry.JSON.encode(json_library) do
161161
{:ok, encoded_transaction} ->
162162
header = ~s({"type":"transaction","length":#{byte_size(encoded_transaction)}})
163163
[header, ?\n, encoded_transaction, ?\n]

lib/sentry/interfaces.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ defmodule Sentry.Interfaces do
306306
]
307307

308308
@doc false
309-
def to_map(%__MODULE__{} = span) do
309+
def to_payload(%__MODULE__{} = span) do
310310
Map.from_struct(span)
311311
end
312312
end

lib/sentry/test.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ defmodule Sentry.Test do
337337
338338
iex> Sentry.Test.start_collecting_sentry_reports()
339339
:ok
340-
iex> Sentry.send_transaction(Sentry.Transaction.new(%{span_id: "123", spans: []}))
340+
iex> Sentry.send_transaction(Sentry.Transaction.new(%{span_id: "123", start_timestamp: "2024-10-12T13:21:13", timestamp: "2024-10-12T13:21:13", spans: []}))
341341
{:ok, ""}
342342
iex> [%Sentry.Transaction{}] = Sentry.Test.pop_sentry_transactions()
343343

lib/sentry/transaction.ex

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,54 @@ defmodule Sentry.Transaction do
77

88
@moduledoc since: "11.0.0"
99

10+
alias Sentry.{Config, UUID, Interfaces.Span, Interfaces.SDK}
11+
1012
@typedoc since: "11.0.0"
13+
@type t() :: %{
14+
# Required
15+
required(:event_id) => <<_::256>>,
16+
required(:start_timestamp) => String.t() | number(),
17+
required(:timestamp) => String.t() | number(),
18+
required(:platform) => :elixir,
19+
required(:contexts) => %{
20+
required(:trace) => %{
21+
required(:trace_id) => String.t(),
22+
required(:span_id) => String.t(),
23+
optional(:parent_span_id) => String.t(),
24+
optional(:op) => String.t(),
25+
optional(:description) => String.t(),
26+
optional(:status) => String.t()
27+
}
28+
},
1129

12-
@type t() :: %__MODULE__{
13-
event_id: String.t(),
14-
environment: String.t(),
15-
transaction: String.t(),
16-
transaction_info: map(),
17-
contexts: map(),
18-
measurements: map(),
19-
type: String.t()
20-
}
30+
# Optional
31+
optional(:environment) => String.t(),
32+
optional(:transaction) => String.t(),
33+
optional(:transaction_info) => map(),
34+
optional(:measurements) => map(),
35+
optional(:type) => String.t(),
36+
optional(:tags) => map(),
37+
optional(:data) => map(),
2138

22-
alias Sentry.{Config, UUID, Interfaces.Span}
39+
# Interfaces
40+
optional(:spans) => [Span.t()],
41+
optional(:sdk) => SDK.t()
42+
}
2343

24-
@enforce_keys [:event_id, :span_id, :spans, :environment]
44+
@enforce_keys [:event_id, :span_id, :start_timestamp, :timestamp]
2545

2646
defstruct @enforce_keys ++
2747
[
48+
:spans,
2849
:transaction,
2950
:transaction_info,
3051
:contexts,
3152
:measurements,
53+
:sdk,
54+
:platform,
55+
:environment,
56+
:tags,
57+
:data,
3258
type: "transaction"
3359
]
3460

@@ -43,24 +69,9 @@ defmodule Sentry.Transaction do
4369
end
4470

4571
@doc false
46-
def to_map(%__MODULE__{} = transaction) do
47-
transaction_attrs =
48-
Map.take(transaction, [
49-
:event_id,
50-
:environment,
51-
:transaction,
52-
:transaction_info,
53-
:contexts,
54-
:measurements,
55-
:type
56-
])
57-
58-
{[root_span], child_spans} = Enum.split_with(transaction.spans, &is_nil(&1.parent_span_id))
59-
60-
root_span
61-
|> Span.to_map()
62-
|> Map.put(:spans, Enum.map(child_spans, &Span.to_map/1))
63-
|> Map.drop([:description])
64-
|> Map.merge(transaction_attrs)
72+
def to_payload(%__MODULE__{} = transaction) do
73+
transaction
74+
|> Map.from_struct()
75+
|> Map.update(:spans, [], fn spans -> Enum.map(spans, &Span.to_payload/1) end)
6576
end
6677
end

test/envelope_test.exs

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

120-
root_span =
121-
%Sentry.Interfaces.Span{
122-
start_timestamp: 1_588_601_261.481_961,
123-
timestamp: 1_588_601_261.488_901,
124-
description: "GET /sockjs-node/info",
125-
op: "http",
126-
span_id: "b01b9f6349558cd1",
127-
parent_span_id: nil,
128-
trace_id: "1e57b752bc6e4544bbaa246cd1d05dee",
129-
tags: %{"http.status_code" => "200"},
130-
data: %{
131-
"url" => "http://localhost:8080/sockjs-node/info?t=1588601703755",
132-
"status_code" => 200,
133-
"type" => "xhr",
134-
"method" => "GET"
135-
}
136-
}
137-
138120
child_spans =
139121
[
140122
%Sentry.Interfaces.Span{
@@ -149,9 +131,25 @@ defmodule Sentry.EnvelopeTest do
149131
]
150132

151133
transaction =
152-
Sentry.Transaction.new(%{
153-
span_id: root_span.span_id,
154-
spans: [root_span | child_spans],
134+
create_transaction(%{
135+
start_timestamp: 1_588_601_261.481_961,
136+
timestamp: 1_588_601_261.488_901,
137+
contexts: %{
138+
trace: %{
139+
trace_id: "1e57b752bc6e4544bbaa246cd1d05dee",
140+
span_id: "b01b9f6349558cd1",
141+
description: "GET /sockjs-node/info",
142+
op: "http"
143+
}
144+
},
145+
tags: %{"http.status_code" => "200"},
146+
data: %{
147+
"url" => "http://localhost:8080/sockjs-node/info?t=1588601703755",
148+
"status_code" => 200,
149+
"type" => "xhr",
150+
"method" => "GET"
151+
},
152+
spans: child_spans,
155153
transaction: "test-transaction"
156154
})
157155

@@ -163,8 +161,8 @@ defmodule Sentry.EnvelopeTest do
163161

164162
assert {:ok, decoded_transaction} = Jason.decode(transaction_line)
165163
assert decoded_transaction["type"] == "transaction"
166-
assert decoded_transaction["start_timestamp"] == root_span.start_timestamp
167-
assert decoded_transaction["timestamp"] == root_span.timestamp
164+
assert decoded_transaction["start_timestamp"] == transaction.start_timestamp
165+
assert decoded_transaction["timestamp"] == transaction.timestamp
168166

169167
assert [span] = decoded_transaction["spans"]
170168

test/sentry/client_report/sender_test.exs

Lines changed: 4 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, Interfaces.Span}
7+
alias Sentry.Event
88

99
setup do
1010
original_retries =
@@ -30,16 +30,15 @@ defmodule Sentry.ClientReportTest do
3030
event_id: Sentry.UUID.uuid4_hex(),
3131
timestamp: "2024-10-12T13:21:13"
3232
},
33-
Transaction.new(%{
34-
span_id: @span_id,
33+
create_transaction(%{
3534
transaction: "test-transaction",
3635
spans: [
37-
%Span{
36+
create_span(%{
3837
span_id: @span_id,
3938
trace_id: Sentry.UUID.uuid4_hex(),
4039
start_timestamp: "2024-10-12T13:21:13",
4140
timestamp: "2024-10-12T13:21:13"
42-
}
41+
})
4342
]
4443
})
4544
]

test/sentry/transaction_test.exs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
defmodule Sentry.TransactionTest do
2+
use Sentry.Case, async: true
3+
4+
alias Sentry.Transaction
5+
6+
import Sentry.TestHelpers
7+
8+
describe "to_payload/1" do
9+
setup do
10+
{:ok, %{transaction: create_transaction()}}
11+
end
12+
13+
test "returns a map representation of the transaction", %{transaction: transaction} do
14+
transaction_payload = Transaction.to_payload(transaction)
15+
16+
[child_span] = transaction_payload[:spans]
17+
18+
assert transaction_payload[:contexts][:trace][:trace_id] == "trace-312"
19+
20+
assert child_span[:parent_span_id] == transaction.span_id
21+
assert child_span[:span_id] == "span-123"
22+
end
23+
end
24+
end

test/sentry_test.exs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,14 @@ defmodule SentryTest do
239239
describe "send_transaction/2" do
240240
setup do
241241
transaction =
242-
Sentry.Transaction.new(%{
243-
span_id: "root-span",
242+
create_transaction(%{
244243
transaction: "test-transaction",
244+
contexts: %{
245+
trace: %{
246+
trace_id: "trace-id",
247+
span_id: "root-span"
248+
}
249+
},
245250
spans: [
246251
%Sentry.Interfaces.Span{
247252
span_id: "root-span",

test/support/test_helpers.ex

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
defmodule Sentry.TestHelpers do
22
import ExUnit.Assertions
33

4+
alias Sentry.Interfaces.Span
5+
alias Sentry.Transaction
6+
47
@spec decode!(String.t()) :: term()
58
def decode!(binary) do
69
assert {:ok, data} = Sentry.JSON.decode(binary, Sentry.Config.json_library())
710
data
811
end
912

10-
@spec decode!(term()) :: String.t()
13+
@spec encode!(term()) :: String.t()
1114
def encode!(data) do
1215
assert {:ok, binary} = Sentry.JSON.encode(data, Sentry.Config.json_library())
1316
binary
@@ -60,6 +63,40 @@ defmodule Sentry.TestHelpers do
6063
decode_envelope_items(rest)
6164
end
6265

66+
def create_span(attrs \\ %{}) do
67+
Map.merge(
68+
%Span{
69+
trace_id: "trace-312",
70+
span_id: "span-123",
71+
start_timestamp: "2025-01-01T00:00:00Z",
72+
timestamp: "2025-01-02T02:03:00Z"
73+
},
74+
attrs
75+
)
76+
end
77+
78+
def create_transaction(attrs \\ %{}) do
79+
Transaction.new(
80+
Map.merge(
81+
%{
82+
span_id: "parent-312",
83+
start_timestamp: "2025-01-01T00:00:00Z",
84+
timestamp: "2025-01-02T02:03:00Z",
85+
contexts: %{
86+
trace: %{
87+
trace_id: "trace-312",
88+
span_id: "parent-312"
89+
}
90+
},
91+
spans: [
92+
create_span(%{parent_span_id: "parent-312"})
93+
]
94+
},
95+
attrs
96+
)
97+
)
98+
end
99+
63100
defp decode_envelope_items(items) do
64101
items
65102
|> Enum.chunk_every(2)

0 commit comments

Comments
 (0)