changed CHANGELOG.md
 
@@ -1,5 1,14 @@
1
1
## CHANGELOG
2
2
3
### `v1.16.0`
4
5
Features
6
7
* Support the W3C Trace Context spec for Distributed Tracing. [#169](https://github.com/newrelic/elixir_agent/pull/169)
8
* Upgrade to New Relic "Protocol 17" which includes support for faster event harvest (sent every 5 seconds!). [#168](https://github.com/newrelic/elixir_agent/pull/168)
9
10
------
11
3
12
### `v1.15.0`
4
13
5
14
Features
changed README.md
 
@@ -99,7 99,7 @@ defmodule MyExternalService do
99
99
@trace {:request, category: :external}
100
100
def request(method, url, headers) do
101
101
NewRelic.set_span(:http, url: url, method: method, component: "HttpClient")
102
- headers NewRelic.create_distributed_trace_payload(:http)
102
headers NewRelic.distributed_trace_headers(:http)
103
103
HttpClient.request(method, url, headers)
104
104
end
105
105
end
changed VERSION
 
@@ -1 1 @@
1
- 1.15.0
1
1.16.0-rc.0
changed hex_metadata.config
 
@@ -20,12 20,17 @@
20
20
<<"lib/new_relic/distributed_trace">>,
21
21
<<"lib/new_relic/distributed_trace/supervisor.ex">>,
22
22
<<"lib/new_relic/distributed_trace/backoff_sampler.ex">>,
23
<<"lib/new_relic/distributed_trace/w3c_trace_context.ex">>,
24
<<"lib/new_relic/distributed_trace/w3c_trace_context">>,
25
<<"lib/new_relic/distributed_trace/w3c_trace_context/trace_parent.ex">>,
26
<<"lib/new_relic/distributed_trace/w3c_trace_context/trace_state.ex">>,
23
27
<<"lib/new_relic/distributed_trace/context.ex">>,
24
28
<<"lib/new_relic/distributed_trace/plug.ex">>,
25
- <<"lib/new_relic/distributed_trace/tracker.ex">>,<<"lib/new_relic/util">>,
26
- <<"lib/new_relic/util/event.ex">>,<<"lib/new_relic/util/error.ex">>,
27
- <<"lib/new_relic/util/vendor.ex">>,<<"lib/new_relic/util/apdex.ex">>,
28
- <<"lib/new_relic/util/request_start.ex">>,
29
<<"lib/new_relic/distributed_trace/tracker.ex">>,
30
<<"lib/new_relic/distributed_trace/new_relic_context.ex">>,
31
<<"lib/new_relic/util">>,<<"lib/new_relic/util/event.ex">>,
32
<<"lib/new_relic/util/error.ex">>,<<"lib/new_relic/util/vendor.ex">>,
33
<<"lib/new_relic/util/apdex.ex">>,<<"lib/new_relic/util/request_start.ex">>,
29
34
<<"lib/new_relic/util/priority_queue.ex">>,<<"lib/new_relic/util/http.ex">>,
30
35
<<"lib/new_relic/util/attr_store.ex">>,<<"lib/new_relic/logger.ex">>,
31
36
<<"lib/new_relic/graceful_shutdown.ex">>,<<"lib/new_relic/aggregate">>,
 
@@ -110,4 115,4 @@
110
115
{<<"optional">>,true},
111
116
{<<"repository">>,<<"hexpm">>},
112
117
{<<"requirement">>,<<"~> 3.3">>}]]}.
113
- {<<"version">>,<<"1.15.0">>}.
118
{<<"version">>,<<"1.16.0-rc.0">>}.
changed lib/new_relic.ex
 
@@ -108,16 108,22 @@ defmodule NewRelic do
108
108
of a Distributed Trace, but outgoing requests need an extra header:
109
109
110
110
```elixir
111
- dt_header_payload = NewRelic.create_distributed_trace_payload(:http)
112
- HTTPoison.get(url, ["x-api-key": "secret"] dt_header_payload)
111
HTTPoison.get(url, ["x-api-key": "secret"] NewRelic.distributed_trace_headers(:http))
113
112
```
114
113
115
114
**Notes:**
116
115
117
- * Call `NewRelic.create_distributed_trace_payload` immediately before making the
116
* Call `NewRelic.distributed_trace_headers` immediately before making the
118
117
request since calling the function marks the "start" time of the request.
119
118
"""
120
- defdelegate create_distributed_trace_payload(type), to: NewRelic.DistributedTrace
119
defdelegate distributed_trace_headers(type), to: NewRelic.DistributedTrace
120
121
@doc """
122
Deprecated, please use `distributed_trace_headers`
123
"""
124
defdelegate create_distributed_trace_payload(type),
125
to: NewRelic.DistributedTrace,
126
as: :distributed_trace_headers
121
127
122
128
@doc """
123
129
To get detailed information about a particular process, you can install a Process sampler.
changed lib/new_relic/config.ex
 
@@ -121,9 121,21 @@ defmodule NewRelic.Config do
121
121
@doc false
122
122
def enabled?, do: (harvest_enabled?() && app_name() && license_key() && true) || false
123
123
124
def event_harvest_config() do
125
%{
126
harvest_limits: %{
127
analytic_event_data:
128
Application.get_env(:new_relic_agent, :analytic_event_per_minute, 1000),
129
custom_event_data: Application.get_env(:new_relic_agent, :custom_event_per_minute, 1000),
130
error_event_data: Application.get_env(:new_relic_agent, :error_event_per_minute, 100),
131
span_event_data: Application.get_env(:new_relic_agent, :span_event_per_minute, 1000)
132
}
133
}
134
end
135
124
136
defp harvest_enabled?,
125
137
do:
126
- System.get_env("NEW_RELIC_HARVEST_ENABLED") ||
138
System.get_env("NEW_RELIC_HARVEST_ENABLED") == "true" ||
127
139
Application.get_env(:new_relic_agent, :harvest_enabled, true)
128
140
129
141
defp parse_app_names(nil), do: nil
changed lib/new_relic/distributed_trace.ex
 
@@ -1,5 1,7 @@
1
1
defmodule NewRelic.DistributedTrace do
2
- @dt_header "newrelic"
2
@nr_header "newrelic"
3
@w3c_traceparent "traceparent"
4
@w3c_tracestate "tracestate"
3
5
4
6
@moduledoc false
5
7
 
@@ -7,21 9,44 @@ defmodule NewRelic.DistributedTrace do
7
9
alias NewRelic.Harvest.Collector.AgentRun
8
10
alias NewRelic.Transaction
9
11
10
- def accept_distributed_trace_payload(:http, conn) do
11
- case Plug.Conn.get_req_header(conn, @dt_header) do
12
- [trace_payload | _] ->
13
- trace_payload
14
- |> Context.decode()
12
def accept_distributed_trace_headers(:http, conn) do
13
w3c_headers(conn) || newrelic_header(conn) || :no_payload
14
end
15
15
16
- [] ->
17
- :no_payload
16
defp w3c_headers(conn) do
17
case Plug.Conn.get_req_header(conn, @w3c_traceparent) do
18
[_traceparent | _] -> NewRelic.DistributedTrace.W3CTraceContext.extract(conn)
19
_ -> false
18
20
end
19
21
end
20
22
21
- def create_distributed_trace_payload(:http) do
23
defp newrelic_header(conn) do
24
case Plug.Conn.get_req_header(conn, @nr_header) do
25
[trace_payload | _] -> NewRelic.DistributedTrace.NewRelicContext.extract(trace_payload)
26
_ -> false
27
end
28
end
29
30
def distributed_trace_headers(:http) do
22
31
case get_tracing_context() do
23
- nil -> []
24
- context -> [{@dt_header, Context.encode(context, get_current_span_guid())}]
32
nil ->
33
[]
34
35
context ->
36
context = %{
37
context
38
| span_guid: get_current_span_guid(),
39
timestamp: System.system_time(:millisecond)
40
}
41
42
nr_header = NewRelic.DistributedTrace.NewRelicContext.generate(context)
43
{traceparent, tracestate} = NewRelic.DistributedTrace.W3CTraceContext.generate(context)
44
45
[
46
{@nr_header, nr_header},
47
{@w3c_traceparent, traceparent},
48
{@w3c_tracestate, tracestate}
49
]
25
50
end
26
51
end
27
52
 
@@ -29,6 54,7 @@ defmodule NewRelic.DistributedTrace do
29
54
{priority, sampled} = generate_sampling()
30
55
31
56
%Context{
57
source: :new,
32
58
account_id: AgentRun.account_id(),
33
59
app_id: AgentRun.primary_application_id(),
34
60
trust_key: AgentRun.trusted_account_key(),
 
@@ -40,18 66,54 @@ defmodule NewRelic.DistributedTrace do
40
66
def track_transaction(context, transport_type: type) do
41
67
context
42
68
|> assign_transaction_guid()
69
|> maybe_generate_sampling()
70
|> maybe_generate_trace_id()
43
71
|> report_attributes(transport_type: type)
72
|> report_attributes(:w3c)
44
73
|> convert_to_outbound()
45
74
|> set_tracing_context()
46
75
end
47
76
77
def maybe_generate_sampling(%Context{sampled: nil, priority: nil} = context) do
78
{priority, sampled} = generate_sampling()
79
%{context | sampled: sampled, priority: priority}
80
end
81
82
def maybe_generate_sampling(context), do: context
83
84
def maybe_generate_trace_id(%Context{parent_id: nil} = context) do
85
%{context | trace_id: generate_guid(16)}
86
end
87
88
def maybe_generate_trace_id(context) do
89
context
90
end
91
92
def report_attributes(
93
%{source: {:w3c, %{tracestate: :non_new_relic}}} = context,
94
transport_type: type
95
) do
96
[
97
"parent.transportType": type,
98
guid: context.trace_id,
99
traceId: context.trace_id,
100
priority: context.priority,
101
sampled: context.sampled,
102
parentId: context.parent_id,
103
parentSpanId: context.span_guid
104
]
105
|> NewRelic.add_attributes()
106
107
context
108
end
109
48
110
def report_attributes(
49
111
%Context{parent_id: nil} = context,
50
112
transport_type: _type
51
113
) do
52
114
[
53
115
guid: context.guid,
54
- traceId: context.guid,
116
traceId: context.trace_id,
55
117
priority: context.priority,
56
118
sampled: context.sampled
57
119
]
 
@@ -79,14 141,28 @@ defmodule NewRelic.DistributedTrace do
79
141
context
80
142
end
81
143
144
def report_attributes(%{source: {:w3c, w3c}} = context, :w3c) do
145
NewRelic.add_attributes(tracingVendors: Enum.join(w3c.tracing_vendors, ","))
146
147
w3c.tracestate == :new_relic &&
148
NewRelic.add_attributes(trustedParentId: w3c.span_id)
149
150
context
151
end
152
153
def report_attributes(context, :w3c) do
154
context
155
end
156
82
157
def convert_to_outbound(%Context{parent_id: nil} = context) do
83
158
%Context{
159
source: context.source,
84
160
account_id: AgentRun.account_id(),
85
161
app_id: AgentRun.primary_application_id(),
86
162
parent_id: nil,
87
163
trust_key: context.trust_key,
88
164
guid: context.guid,
89
- trace_id: context.guid,
165
trace_id: context.trace_id,
90
166
priority: context.priority,
91
167
sampled: context.sampled
92
168
}
 
@@ -94,6 170,7 @@ defmodule NewRelic.DistributedTrace do
94
170
95
171
def convert_to_outbound(%Context{} = context) do
96
172
%Context{
173
source: context.source,
97
174
account_id: AgentRun.account_id(),
98
175
app_id: AgentRun.primary_application_id(),
99
176
parent_id: context.guid,
 
@@ -181,13 258,16 @@ defmodule NewRelic.DistributedTrace do
181
258
NewRelic.DistributedTrace.BackoffSampler.sample?()
182
259
end
183
260
184
- defp generate_priority, do: :rand.uniform() |> Float.round(6)
261
defp generate_priority do
262
:rand.uniform() |> Float.round(6)
263
end
185
264
186
265
def assign_transaction_guid(context) do
187
266
Map.put(context, :guid, generate_guid())
188
267
end
189
268
190
269
def generate_guid(), do: :crypto.strong_rand_bytes(8) |> Base.encode16() |> String.downcase()
270
def generate_guid(16), do: :crypto.strong_rand_bytes(16) |> Base.encode16() |> String.downcase()
191
271
def generate_guid(pid: pid), do: encode_guid([pid, node()])
192
272
def generate_guid(pid: pid, label: label, ref: ref), do: encode_guid([label, ref, pid, node()])
193
273
 
@@ -203,7 283,7 @@ defmodule NewRelic.DistributedTrace do
203
283
|> :erlang.phash2()
204
284
|> Integer.to_charlist(16)
205
285
|> to_string()
206
- |> String.slice(0..4)
286
|> String.slice(0..3)
207
287
|> String.downcase()
208
288
end
changed lib/new_relic/distributed_trace/context.ex
 
@@ -1,12 1,9 @@
1
1
defmodule NewRelic.DistributedTrace.Context do
2
- # Struct containing the DT payload context
3
-
4
2
@moduledoc false
5
3
6
- @payload_version [0, 1]
7
-
8
4
defstruct type: "App",
9
- version: @payload_version,
5
source: nil,
6
version: nil,
10
7
account_id: nil,
11
8
app_id: nil,
12
9
parent_id: nil,
 
@@ -15,79 12,6 @@ defmodule NewRelic.DistributedTrace.Context do
15
12
trace_id: nil,
16
13
trust_key: nil,
17
14
priority: nil,
18
- sampled: false,
15
sampled: nil,
19
16
timestamp: nil
20
-
21
- def decode(raw_payload) when is_binary(raw_payload) do
22
- with {:ok, json} <- Base.decode64(raw_payload),
23
- {:ok, map} <- Jason.decode(json),
24
- context <- validate(map) do
25
- NewRelic.report_metric(:supportability, [:dt, :accept, :success])
26
- context
27
- else
28
- error ->
29
- NewRelic.report_metric(:supportability, [:dt, :accept, :parse_error])
30
- NewRelic.log(:debug, "Bad DT Payload: #{inspect(error)} #{inspect(raw_payload)}")
31
- nil
32
- end
33
- end
34
-
35
- def validate(%{
36
- "v" => @payload_version,
37
- "d" =>
38
- %{
39
- "ty" => type,
40
- "ac" => account_id,
41
- "ap" => app_id,
42
- "tr" => trace_id,
43
- "ti" => timestamp
44
- } = data
45
- }) do
46
- %__MODULE__{
47
- version: @payload_version,
48
- type: type,
49
- account_id: account_id,
50
- app_id: app_id,
51
- parent_id: data["tx"],
52
- span_guid: data["id"],
53
- trace_id: trace_id,
54
- trust_key: data["tk"],
55
- priority: data["pr"],
56
- sampled: data["sa"] || false,
57
- timestamp: timestamp
58
- }
59
- end
60
-
61
- def validate(_invalid), do: :invalid
62
-
63
- def encode(context, current_span_guid) do
64
- %{
65
- "v" => @payload_version,
66
- "d" =>
67
- %{
68
- "ty" => context.type,
69
- "ac" => context.account_id,
70
- "ap" => context.app_id,
71
- "tx" => context.guid,
72
- "tr" => context.trace_id,
73
- "pr" => context.priority,
74
- "sa" => context.sampled,
75
- "ti" => System.system_time(:millisecond)
76
- }
77
- |> maybe_put(:span_guid, "id", context.sampled, current_span_guid)
78
- |> maybe_put(:trust_key, "tk", context.account_id, context.trust_key)
79
- }
80
- |> Jason.encode!()
81
- |> Base.encode64()
82
- end
83
-
84
- def maybe_put(data, :span_guid, key, true = _sampled, guid), do: Map.put(data, key, guid)
85
- def maybe_put(data, :span_guid, _key, false = _sampled, _guid), do: data
86
-
87
- def maybe_put(data, :trust_key, _key, account_id, account_id), do: data
88
- def maybe_put(data, :trust_key, _key, _account_id, nil), do: data
89
- def maybe_put(data, :trust_key, key, _account_id, trust_key), do: Map.put(data, key, trust_key)
90
-
91
- def parse_int(nil), do: :error
92
- def parse_int(field), do: Integer.parse(field)
93
17
end
added lib/new_relic/distributed_trace/new_relic_context.ex
 
@@ -0,0 1,96 @@
1
defmodule NewRelic.DistributedTrace.NewRelicContext do
2
alias NewRelic.DistributedTrace.Context
3
alias NewRelic.Harvest.Collector.AgentRun
4
5
def extract(trace_payload) do
6
decode(trace_payload)
7
|> restrict_access
8
end
9
10
def generate(context) do
11
encode(context)
12
end
13
14
def decode(raw_payload) when is_binary(raw_payload) do
15
with {:ok, json} <- Base.decode64(raw_payload),
16
{:ok, map} <- Jason.decode(json),
17
context <- validate(map) do
18
NewRelic.report_metric(:supportability, [:dt, :accept, :success])
19
context
20
else
21
error ->
22
NewRelic.report_metric(:supportability, [:dt, :accept, :parse_error])
23
NewRelic.log(:debug, "Bad DT Payload: #{inspect(error)} #{inspect(raw_payload)}")
24
nil
25
end
26
end
27
28
def restrict_access(context) do
29
if (context.trust_key || context.account_id) == AgentRun.trusted_account_key() do
30
context
31
else
32
:restricted
33
end
34
end
35
36
@payload_version [0, 1]
37
def validate(%{
38
"v" => @payload_version,
39
"d" =>
40
%{
41
"ty" => type,
42
"ac" => account_id,
43
"ap" => app_id,
44
"tr" => trace_id,
45
"ti" => timestamp
46
} = data
47
}) do
48
%Context{
49
source: :new_relic,
50
version: @payload_version,
51
type: type,
52
account_id: account_id,
53
app_id: app_id,
54
parent_id: data["tx"],
55
span_guid: data["id"],
56
trace_id: trace_id,
57
trust_key: data["tk"],
58
priority: data["pr"],
59
sampled: data["sa"] || false,
60
timestamp: timestamp
61
}
62
end
63
64
def validate(_invalid), do: :invalid
65
66
def encode(context) do
67
%{
68
"v" => @payload_version,
69
"d" =>
70
%{
71
"ty" => context.type,
72
"ac" => context.account_id,
73
"ap" => context.app_id,
74
"tx" => context.guid,
75
"tr" => context.trace_id,
76
"pr" => context.priority,
77
"sa" => context.sampled,
78
"ti" => context.timestamp
79
}
80
|> maybe_put(:span_guid, "id", context.sampled, context.span_guid)
81
|> maybe_put(:trust_key, "tk", context.account_id, context.trust_key)
82
}
83
|> Jason.encode!()
84
|> Base.encode64()
85
end
86
87
def maybe_put(data, :span_guid, key, true = _sampled, guid), do: Map.put(data, key, guid)
88
def maybe_put(data, :span_guid, _key, false = _sampled, _guid), do: data
89
90
def maybe_put(data, :trust_key, _key, account_id, account_id), do: data
91
def maybe_put(data, :trust_key, _key, _account_id, nil), do: data
92
def maybe_put(data, :trust_key, key, _account_id, trust_key), do: Map.put(data, key, trust_key)
93
94
def parse_int(nil), do: :error
95
def parse_int(field), do: Integer.parse(field)
96
end
changed lib/new_relic/distributed_trace/plug.ex
 
@@ -9,7 9,6 @@ defmodule NewRelic.DistributedTrace.Plug do
9
9
10
10
alias NewRelic.DistributedTrace
11
11
alias NewRelic.DistributedTrace.Context
12
- alias NewRelic.Harvest.Collector.AgentRun
13
12
14
13
@impl Plug
15
14
def init(opts), do: opts
 
@@ -42,19 41,9 @@ defmodule NewRelic.DistributedTrace.Plug do
42
41
end
43
42
44
43
defp determine_context(conn) do
45
- with %Context{} = context <- DistributedTrace.accept_distributed_trace_payload(:http, conn),
46
- %Context{} = context <- restrict_access(context) do
47
- context
48
- else
44
case DistributedTrace.accept_distributed_trace_headers(:http, conn) do
45
%Context{} = context -> context
49
46
_ -> DistributedTrace.generate_new_context()
50
47
end
51
48
end
52
-
53
- def restrict_access(context) do
54
- if (context.trust_key || context.account_id) == AgentRun.trusted_account_key() do
55
- context
56
- else
57
- :restricted
58
- end
59
- end
60
49
end
added lib/new_relic/distributed_trace/w3c_trace_context.ex
 
@@ -0,0 1,105 @@
1
defmodule NewRelic.DistributedTrace.W3CTraceContext do
2
@moduledoc false
3
4
alias NewRelic.Harvest.Collector.AgentRun
5
alias NewRelic.DistributedTrace.Context
6
alias __MODULE__.{TraceParent, TraceState}
7
8
@w3c_traceparent "traceparent"
9
@w3c_tracestate "tracestate"
10
11
def extract(conn) do
12
with traceparent_header <- Plug.Conn.get_req_header(conn, @w3c_traceparent),
13
tracestate_header <- Plug.Conn.get_req_header(conn, @w3c_tracestate),
14
%TraceParent{} = traceparent <- TraceParent.decode(traceparent_header),
15
%TraceState{} = tracestate <- TraceState.decode(tracestate_header) do
16
case TraceState.restrict_access(tracestate) do
17
{newrelic, others} ->
18
NewRelic.report_metric(:supportability, [:trace_context, :accept, :success])
19
20
%Context{
21
source:
22
{:w3c,
23
%{
24
tracestate: :new_relic,
25
sampled: traceparent.flags.sampled,
26
others: others,
27
span_id: newrelic.span_id,
28
tracing_vendors: Enum.map(others, & &1.key)
29
}},
30
type: newrelic.parent_type,
31
account_id: newrelic.account_id,
32
app_id: newrelic.app_id,
33
parent_id: newrelic.transaction_id,
34
span_guid: traceparent.parent_id,
35
trace_id: traceparent.trace_id,
36
trust_key: newrelic.trusted_account_key,
37
priority: newrelic.priority,
38
sampled: newrelic.sampled,
39
timestamp: newrelic.timestamp
40
}
41
42
others ->
43
NewRelic.report_metric(:supportability, [:trace_context, :accept, :success])
44
NewRelic.report_metric(:supportability, [:trace_context, :tracestate, :non_new_relic])
45
46
%Context{
47
source:
48
{:w3c,
49
%{
50
tracestate: :non_new_relic,
51
sampled: traceparent.flags.sampled,
52
others: others,
53
tracing_vendors: Enum.map(others, & &1.key)
54
}},
55
parent_id: traceparent.parent_id,
56
span_guid: traceparent.parent_id,
57
trace_id: traceparent.trace_id,
58
trust_key: AgentRun.trusted_account_key()
59
}
60
end
61
else
62
_ ->
63
NewRelic.report_metric(:supportability, [:trace_context, :accept, :exception])
64
false
65
end
66
end
67
68
def generate(%{source: source} = context) do
69
{others, traceparent_sampled} =
70
case source do
71
{:w3c, %{others: others, sampled: sampled}} -> {others, sampled}
72
_ -> {[], context.sampled}
73
end
74
75
traceparent =
76
TraceParent.encode(%TraceParent{
77
trace_id: context.trace_id,
78
parent_id: context.span_guid,
79
flags: %{sampled: traceparent_sampled}
80
})
81
82
tracestate =
83
TraceState.encode(%TraceState{
84
members: [
85
%{
86
key: :new_relic,
87
value: %TraceState.NewRelicState{
88
trusted_account_key: context.trust_key,
89
parent_type: context.type,
90
account_id: context.account_id,
91
app_id: context.app_id,
92
span_id: context.span_guid,
93
transaction_id: context.parent_id,
94
sampled: context.sampled,
95
priority: context.priority,
96
timestamp: context.timestamp
97
}
98
}
99
| others
100
]
101
})
102
103
{traceparent, tracestate}
104
end
105
end
added lib/new_relic/distributed_trace/w3c_trace_context/trace_parent.ex
 
@@ -0,0 1,96 @@
1
defmodule NewRelic.DistributedTrace.W3CTraceContext.TraceParent do
2
@moduledoc false
3
4
# https://w3c.github.io/trace-context/#traceparent-header
5
6
defstruct version: "00",
7
trace_id: nil,
8
parent_id: nil,
9
flags: nil
10
11
@version 2
12
@trace_id 32
13
@parent_id 16
14
@flags 2
15
16
def decode([header]), do: decode(header)
17
18
def decode(<<"ff", "-", _::binary>>),
19
do: invalid()
20
21
def decode(<<_::binary-size(@version), "-", "00000000000000000000000000000000", _::binary>>),
22
do: invalid()
23
24
def decode(
25
<<_::binary-size(@version), "-", _::binary-size(@trace_id), "-", "0000000000000000",
26
_::binary>>
27
),
28
do: invalid()
29
30
def decode(
31
<<version::binary-size(@version), "-", trace_id::binary-size(@trace_id), "-",
32
parent_id::binary-size(@parent_id), "-", flags::binary-size(@flags)>>
33
) do
34
validate(
35
[version, trace_id, parent_id, flags],
36
%__MODULE__{
37
version: version,
38
trace_id: trace_id,
39
parent_id: parent_id,
40
flags: %{sampled: flags == "01"}
41
}
42
)
43
end
44
45
# Future versions can be longer
46
def decode(
47
<<version::binary-size(@version), "-", trace_id::binary-size(@trace_id), "-",
48
parent_id::binary-size(@parent_id), "-", flags::binary-size(@flags), "-", _::binary>>
49
)
50
when version != "00" do
51
validate(
52
[version, trace_id, parent_id, flags],
53
%__MODULE__{
54
version: version,
55
trace_id: trace_id,
56
parent_id: parent_id,
57
flags: %{sampled: flags == "01"}
58
}
59
)
60
end
61
62
def decode(_),
63
do: invalid()
64
65
def encode(%__MODULE__{
66
version: _version,
67
trace_id: trace_id,
68
parent_id: parent_id,
69
flags: %{
70
sampled: sampled
71
}
72
}) do
73
[
74
"00",
75
String.pad_leading(trace_id, @trace_id, "0") |> String.downcase(),
76
String.pad_leading(parent_id, @parent_id, "0") |> String.downcase(),
77
(sampled && "01") || "00"
78
]
79
|> Enum.join("-")
80
end
81
82
defp invalid() do
83
NewRelic.report_metric(:supportability, [:trace_context, :traceparent, :invalid])
84
:invalid
85
end
86
87
defp validate(values, context) do
88
case Enum.all?(values, &valid?/1) do
89
true -> context
90
false -> :invalid
91
end
92
end
93
94
defp valid?(value),
95
do: Base.decode16(value, case: :mixed) != :error
96
end
added lib/new_relic/distributed_trace/w3c_trace_context/trace_state.ex
 
@@ -0,0 1,178 @@
1
defmodule NewRelic.DistributedTrace.W3CTraceContext.TraceState do
2
@moduledoc false
3
4
# https://w3c.github.io/trace-context/#tracestate-header
5
6
alias NewRelic.Harvest.Collector.AgentRun
7
8
defstruct [:members]
9
10
defmodule NewRelicState do
11
defstruct version: "0",
12
trusted_account_key: nil,
13
parent_type: nil,
14
account_id: nil,
15
app_id: nil,
16
span_id: nil,
17
transaction_id: nil,
18
sampled: nil,
19
priority: nil,
20
timestamp: nil
21
end
22
23
def encode(%__MODULE__{members: members}) do
24
members
25
|> Enum.take(32)
26
|> Enum.map(&encode/1)
27
|> Enum.join(",")
28
end
29
30
def encode(%{key: :new_relic, value: value}) do
31
encoded_value =
32
[
33
value.version,
34
value.parent_type |> encode_type(),
35
value.account_id,
36
value.app_id,
37
value.span_id,
38
value.transaction_id,
39
value.sampled |> encode_sampled(),
40
value.priority,
41
value.timestamp
42
]
43
|> Enum.join("-")
44
45
"#{value.trusted_account_key}@nr=#{encoded_value}"
46
end
47
48
def encode(%{key: key, value: value}) do
49
"#{key}=#{value}"
50
end
51
52
def decode([]), do: %__MODULE__{members: []}
53
54
def decode([header]) when is_binary(header) do
55
members =
56
header
57
|> String.split(",")
58
|> Enum.map(&String.trim/1)
59
|> Enum.map(&String.split(&1, "="))
60
|> Enum.reject(&(&1 == [""]))
61
62
%__MODULE__{members: validate(members)}
63
end
64
65
def restrict_access(%__MODULE__{members: members}) do
66
members
67
|> Enum.split_with(&matching_new_relic_state?/1)
68
|> case do
69
{[%{value: new_relic}], others} -> {new_relic, others}
70
{_, others} -> others
71
end
72
end
73
74
def matching_new_relic_state?(context) do
75
context.key == :new_relic &&
76
context.value.trusted_account_key == AgentRun.trusted_account_key()
77
end
78
79
defp validate(members) do
80
case valid_members?(members) do
81
true -> Enum.flat_map(members, &decode_member/1)
82
false -> []
83
end
84
end
85
86
defp valid_members?(members) do
87
Enum.all?(members, &valid_member?/1) &&
88
no_duplicate_keys(members) &&
89
length(members) <= 32
90
end
91
92
@key_wo_vendor ~r/^[0-9a-z][_0-9a-z\-\*\/]{0,255}$/
93
@key_with_vendor ~r/^[0-9a-z][_0-9a-z\-\*\/]{0,240}@[0-9a-z][_0-9a-z\-\*\/]{0,13}$/
94
@value ~r/^([\x20-\x2b\x2d-\x3c\x3e-\x7e]{0,255}[\x21-\x2b\x2d-\x3c\x3e-\x7e])$/
95
defp valid_member?([key, value]) do
96
valid_key? = Regex.match?(@key_wo_vendor, key) || Regex.match?(@key_with_vendor, key)
97
valid_value? = Regex.match?(@value, value)
98
99
valid_key? && valid_value?
100
end
101
102
defp valid_member?(_) do
103
false
104
end
105
106
defp no_duplicate_keys(members) do
107
keys = Enum.map(members, &List.first/1)
108
duplicates? = length(keys) != length(Enum.uniq(keys))
109
110
!duplicates?
111
end
112
113
defp decode_member([key, value]) do
114
decode_member(vendor_type(key), key, value)
115
end
116
117
defp decode_member(:new_relic, key, value) do
118
[
119
version,
120
parent_type,
121
account_id,
122
app_id,
123
span_id,
124
transaction_id,
125
sampled,
126
priority,
127
timestamp
128
] = String.split(value, "-")
129
130
[trusted_account_key, _] = String.split(key, "@")
131
132
[
133
%{
134
key: :new_relic,
135
value: %__MODULE__.NewRelicState{
136
trusted_account_key: trusted_account_key,
137
version: version |> String.to_integer(),
138
parent_type: parent_type |> decode_type(),
139
account_id: account_id,
140
app_id: app_id,
141
span_id: span_id,
142
transaction_id: transaction_id,
143
sampled: sampled |> decode_sampled(),
144
priority: priority |> decode_priority(),
145
timestamp: timestamp |> String.to_integer()
146
}
147
}
148
]
149
end
150
151
defp decode_member(:other, key, value) do
152
[
153
%{key: key, value: value}
154
]
155
end
156
157
defp vendor_type(key) do
158
if String.contains?(key, "@nr"), do: :new_relic, else: :other
159
end
160
161
defp decode_type("0"), do: "App"
162
defp decode_type("1"), do: "Browser"
163
defp decode_type("2"), do: "Mobile"
164
165
defp encode_type("App"), do: "0"
166
defp encode_type("Browser"), do: "1"
167
defp encode_type("Mobile"), do: "2"
168
169
defp decode_priority(""), do: nil
170
defp decode_priority(priority), do: String.to_float(priority)
171
172
defp decode_sampled("1"), do: true
173
defp decode_sampled("0"), do: false
174
defp decode_sampled(""), do: nil
175
176
defp encode_sampled(true), do: "1"
177
defp encode_sampled(false), do: "0"
178
end
changed lib/new_relic/harvest/collector/agent_run.ex
 
@@ -69,24 69,50 @@ defmodule NewRelic.Harvest.Collector.AgentRun do
69
69
store(:account_id, connect_response["account_id"])
70
70
store(:primary_application_id, connect_response["primary_application_id"])
71
71
72
store(:request_headers, connect_response["request_headers_map"] |> Map.to_list())
73
72
74
store(:sampling_target, connect_response["sampling_target"])
73
75
store(:sampling_target_period, connect_response["sampling_target_period_in_seconds"] * 1000)
74
76
75
- transaction_event = connect_response["data_methods"]["analytic_event_data"]
76
- store(:transaction_event_reservoir_size, transaction_event["max_samples_stored"])
77
- store(:transaction_event_harvest_cycle, transaction_event["report_period_in_seconds"] * 1000)
77
connect_response["data_methods"]
78
event_harvest = connect_response["event_harvest_config"]
79
harvest_limits = event_harvest["harvest_limits"]
78
80
79
- custom_event = connect_response["data_methods"]["custom_event_data"]
80
- store(:custom_event_reservoir_size, custom_event["max_samples_stored"])
81
- store(:custom_event_harvest_cycle, custom_event["report_period_in_seconds"] * 1000)
81
if harvest_limits["analytic_event_data"] do
82
store(:transaction_event_reservoir_size, harvest_limits["analytic_event_data"])
83
store(:transaction_event_harvest_cycle, event_harvest["report_period_ms"])
84
else
85
analytic_event = connect_response["data_methods"]["analytic_event_data"]
86
store(:transaction_event_reservoir_size, analytic_event["max_samples_stored"])
87
store(:transaction_event_harvest_cycle, analytic_event["report_period_in_seconds"] * 1000)
88
end
82
89
83
- error_event = connect_response["data_methods"]["error_event_data"]
84
- store(:error_event_reservoir_size, error_event["max_samples_stored"])
85
- store(:error_event_harvest_cycle, error_event["report_period_in_seconds"] * 1000)
90
if harvest_limits["custom_event_data"] do
91
store(:custom_event_reservoir_size, harvest_limits["custom_event_data"])
92
store(:custom_event_harvest_cycle, event_harvest["report_period_ms"])
93
else
94
custom_event = connect_response["data_methods"]["custom_event_data"]
95
store(:custom_event_reservoir_size, custom_event["max_samples_stored"])
96
store(:custom_event_harvest_cycle, custom_event["report_period_in_seconds"] * 1000)
97
end
86
98
87
- span_event = connect_response["data_methods"]["span_event_data"]
88
- store(:span_event_reservoir_size, span_event["max_samples_stored"])
89
- store(:span_event_harvest_cycle, span_event["report_period_in_seconds"] * 1000)
99
if harvest_limits["error_event_data"] do
100
store(:error_event_reservoir_size, harvest_limits["error_event_data"])
101
store(:error_event_harvest_cycle, event_harvest["report_period_ms"])
102
else
103
error_event = connect_response["data_methods"]["error_event_data"]
104
store(:error_event_reservoir_size, error_event["max_samples_stored"])
105
store(:error_event_harvest_cycle, error_event["report_period_in_seconds"] * 1000)
106
end
107
108
if harvest_limits["span_event_data"] do
109
store(:span_event_reservoir_size, harvest_limits["span_event_data"])
110
store(:span_event_harvest_cycle, event_harvest["report_period_ms"])
111
else
112
span_event = connect_response["data_methods"]["span_event_data"]
113
store(:span_event_reservoir_size, span_event["max_samples_stored"])
114
store(:span_event_harvest_cycle, span_event["report_period_in_seconds"] * 1000)
115
end
90
116
91
117
store(:data_report_period, connect_response["data_report_period"] * 1000)
92
118
 
@@ -103,11 129,11 @@ defmodule NewRelic.Harvest.Collector.AgentRun do
103
129
:ets.insert(__MODULE__, {key, value})
104
130
end
105
131
106
- def lookup(key) do
132
def lookup(key, default \\ nil) do
107
133
Application.get_env(:new_relic_agent, key) ||
108
134
case :ets.lookup(__MODULE__, key) do
109
135
[{^key, value}] -> value
110
- [] -> nil
136
[] -> default
111
137
end
112
138
end
113
139
end
changed lib/new_relic/harvest/collector/connect.ex
 
@@ -13,6 13,7 @@ defmodule NewRelic.Harvest.Collector.Connect do
13
13
%{label_type: key, label_value: value}
14
14
end),
15
15
utilization: NewRelic.Util.utilization(),
16
event_harvest_config: NewRelic.Config.event_harvest_config(),
16
17
metadata: NewRelic.Util.metadata(),
17
18
environment: NewRelic.Util.elixir_environment(),
18
19
agent_version: NewRelic.Config.agent_version()
changed lib/new_relic/harvest/collector/custom_event/harvester.ex
 
@@ -17,7 17,7 @@ defmodule NewRelic.Harvest.Collector.CustomEvent.Harvester do
17
17
start_time_mono: System.monotonic_time(),
18
18
end_time_mono: nil,
19
19
sampling: %{
20
- reservoir_size: Collector.AgentRun.lookup(:custom_event_reservoir_size),
20
reservoir_size: Collector.AgentRun.lookup(:custom_event_reservoir_size, 100),
21
21
events_seen: 0
22
22
},
23
23
custom_events: []
 
@@ -90,11 90,12 @@ defmodule NewRelic.Harvest.Collector.CustomEvent.Harvester do
90
90
def send_harvest(state) do
91
91
events = build_payload(state)
92
92
Collector.Protocol.custom_event([Collector.AgentRun.agent_run_id(), state.sampling, events])
93
- log_harvest(length(events))
93
log_harvest(length(events), state.sampling.reservoir_size)
94
94
end
95
95
96
- def log_harvest(harvest_size) do
97
- NewRelic.report_metric({:supportability, CustomEvent}, harvest_size: harvest_size)
96
def log_harvest(harvest_size, reservoir_size) do
97
NewRelic.report_metric({:supportability, "CustomEventData"}, harvest_size: harvest_size)
98
NewRelic.report_metric({:supportability, "CustomEventData"}, reservoir_size: reservoir_size)
98
99
NewRelic.log(:debug, "Completed Custom Event harvest - size: #{harvest_size}")
99
100
end
changed lib/new_relic/harvest/collector/error_trace/harvester.ex
 
@@ -76,7 76,7 @@ defmodule NewRelic.Harvest.Collector.ErrorTrace.Harvester do
76
76
end
77
77
78
78
def log_harvest(harvest_size) do
79
- NewRelic.report_metric({:supportability, ErrorTrace}, harvest_size: harvest_size)
79
NewRelic.report_metric({:supportability, "ErrorData"}, harvest_size: harvest_size)
80
80
NewRelic.log(:debug, "Completed Error Trace harvest - size: #{harvest_size}")
81
81
end
changed lib/new_relic/harvest/collector/metric/harvester.ex
 
@@ -74,7 74,7 @@ defmodule NewRelic.Harvest.Collector.Metric.Harvester do
74
74
end
75
75
76
76
def log_harvest(harvest_size) do
77
- NewRelic.report_metric({:supportability, Metric}, harvest_size: harvest_size)
77
NewRelic.report_metric({:supportability, "MetricData"}, harvest_size: harvest_size)
78
78
NewRelic.log(:debug, "Completed Metric harvest - size: #{harvest_size}")
79
79
end
changed lib/new_relic/harvest/collector/metric_data.ex
 
@@ -245,11 245,21 @@ defmodule NewRelic.Harvest.Collector.MetricData do
245
245
}
246
246
]
247
247
248
def transform({:supportability, harvester}, reservoir_size: reservoir_size),
249
do: [
250
%Metric{
251
name: join(["Supportability/EventHarvest", harvester, "HarvestLimit"]),
252
call_count: 1,
253
total_call_time: reservoir_size
254
}
255
]
256
248
257
def transform({:supportability, harvester}, harvest_size: harvest_size),
249
258
do: [
250
259
%Metric{
251
- name: join(["Supportability/Elixir/Collector/HarvestSize", inspect(harvester)]),
252
- call_count: harvest_size
260
name: join(["Supportability/Elixir/Collector/HarvestSize", harvester]),
261
call_count: 1,
262
total_call_time: harvest_size
253
263
},
254
264
%Metric{
255
265
name: :"Supportability/Elixir/Harvest",
 
@@ -261,12 271,29 @@ defmodule NewRelic.Harvest.Collector.MetricData do
261
271
}
262
272
]
263
273
274
def transform(:supportability, [:trace_context, :accept, :success]),
275
do: [
276
%Metric{name: :"Supportability/TraceContext/Accept/Success", call_count: 1}
277
]
278
279
def transform(:supportability, [:trace_context, :accept, :exception]),
280
do: [
281
%Metric{name: :"Supportability/TraceContext/Accept/Exception", call_count: 1}
282
]
283
284
def transform(:supportability, [:trace_context, :tracestate, :non_new_relic]),
285
do: [
286
%Metric{name: :"Supportability/TraceContext/TraceState/NoNrEntry", call_count: 1}
287
]
288
289
def transform(:supportability, [:trace_context, :traceparent, :invalid]),
290
do: [
291
%Metric{name: :"Supportability/TraceContext/TraceParent/Parse/Exception", call_count: 1}
292
]
293
264
294
def transform(:supportability, [:dt, :accept, :success]),
265
295
do: [
266
- %Metric{
267
- name: :"Supportability/DistributedTrace/AcceptPayload/Success",
268
- call_count: 1
269
- }
296
%Metric{name: :"Supportability/DistributedTrace/AcceptPayload/Success", call_count: 1}
270
297
]
271
298
272
299
def transform(:supportability, [:dt, :accept, :parse_error]),
changed lib/new_relic/harvest/collector/protocol.ex
 
@@ -3,7 3,7 @@ defmodule NewRelic.Harvest.Collector.Protocol do
3
3
4
4
@moduledoc false
5
5
6
- @protocol_version 16
6
@protocol_version 17
7
7
8
8
def preconnect,
9
9
do: call_remote(%{method: "preconnect"}, [])
 
@@ -76,7 76,8 @@ defmodule NewRelic.Harvest.Collector.Protocol do
76
76
|> URI.to_string()
77
77
end
78
78
79
- defp parse_http_response({:ok, %{status_code: 200, body: body}}, _params) do
79
defp parse_http_response({:ok, %{status_code: status_code, body: body}}, _params)
80
when status_code in [200, 410] do
80
81
case Jason.decode(body) do
81
82
{:ok, response} ->
82
83
{:ok, response}
 
@@ -87,6 88,10 @@ defmodule NewRelic.Harvest.Collector.Protocol do
87
88
end
88
89
end
89
90
91
defp parse_http_response({:ok, %{status_code: 202}}, _params) do
92
{:ok, :accepted}
93
end
94
90
95
defp parse_http_response({:ok, %{status_code: status, body: body}}, params) do
91
96
NewRelic.log(:error, "#{params[:method]}: (#{status}) #{body}")
92
97
{:error, status}
 
@@ -114,6 119,10 @@ defmodule NewRelic.Harvest.Collector.Protocol do
114
119
{:error, exception_type}
115
120
end
116
121
122
defp parse_collector_response({:ok, :accepted}, _params) do
123
{:ok, :accepted}
124
end
125
117
126
defp parse_collector_response({:error, reason}, _params) do
118
127
{:error, reason}
119
128
end
 
@@ -160,8 169,10 @@ defmodule NewRelic.Harvest.Collector.Protocol do
160
169
:unexpected_exception
161
170
end
162
171
163
- defp collector_headers,
164
- do: ["user-agent": "NewRelic-ElixirAgent/#{NewRelic.Config.agent_version()}"]
172
defp collector_headers do
173
["user-agent": "NewRelic-ElixirAgent/#{NewRelic.Config.agent_version()}"]
174
Collector.AgentRun.lookup(:request_headers, [])
175
end
165
176
166
177
defp default_collector_params,
167
178
do: %{
changed lib/new_relic/harvest/collector/span_event/harvester.ex
 
@@ -19,7 19,7 @@ defmodule NewRelic.Harvest.Collector.SpanEvent.Harvester do
19
19
start_time_mono: System.monotonic_time(),
20
20
end_time_mono: nil,
21
21
sampling: %{
22
- reservoir_size: Collector.AgentRun.lookup(:span_event_reservoir_size),
22
reservoir_size: Collector.AgentRun.lookup(:span_event_reservoir_size, 100),
23
23
events_seen: 0
24
24
},
25
25
events: PriorityQueue.new()
 
@@ -131,7 131,7 @@ defmodule NewRelic.Harvest.Collector.SpanEvent.Harvester do
131
131
spans
132
132
])
133
133
134
- log_harvest(length(spans))
134
log_harvest(length(spans), state.sampling.reservoir_size)
135
135
end
136
136
137
137
def generate_guid(:root), do: DistributedTrace.generate_guid(pid: self())
 
@@ -139,8 139,9 @@ defmodule NewRelic.Harvest.Collector.SpanEvent.Harvester do
139
139
def generate_guid({label, ref}),
140
140
do: DistributedTrace.generate_guid(pid: self(), label: label, ref: ref)
141
141
142
- def log_harvest(harvest_size) do
143
- NewRelic.report_metric({:supportability, SpanEvent}, harvest_size: harvest_size)
142
def log_harvest(harvest_size, reservoir_size) do
143
NewRelic.report_metric({:supportability, "SpanEventData"}, harvest_size: harvest_size)
144
NewRelic.report_metric({:supportability, "SpanEventData"}, reservoir_size: reservoir_size)
144
145
NewRelic.log(:debug, "Completed Span Event harvest - size: #{harvest_size}")
145
146
end
changed lib/new_relic/harvest/collector/transaction_error_event/harvester.ex
 
@@ -17,7 17,7 @@ defmodule NewRelic.Harvest.Collector.TransactionErrorEvent.Harvester do
17
17
start_time_mono: System.monotonic_time(),
18
18
end_time_mono: nil,
19
19
sampling: %{
20
- reservoir_size: Collector.AgentRun.lookup(:error_event_reservoir_size),
20
reservoir_size: Collector.AgentRun.lookup(:error_event_reservoir_size, 10),
21
21
events_seen: 0
22
22
},
23
23
error_events: []
 
@@ -80,7 80,7 @@ defmodule NewRelic.Harvest.Collector.TransactionErrorEvent.Harvester do
80
80
end
81
81
82
82
def log_harvest(harvest_size) do
83
- NewRelic.report_metric({:supportability, TransactionErrorEvent}, harvest_size: harvest_size)
83
NewRelic.report_metric({:supportability, "ErrorEventData"}, harvest_size: harvest_size)
84
84
NewRelic.log(:debug, "Completed Error Event harvest - size: #{harvest_size}")
85
85
end
changed lib/new_relic/harvest/collector/transaction_event/harvester.ex
 
@@ -18,7 18,7 @@ defmodule NewRelic.Harvest.Collector.TransactionEvent.Harvester do
18
18
start_time_mono: System.monotonic_time(),
19
19
end_time_mono: nil,
20
20
sampling: %{
21
- reservoir_size: Collector.AgentRun.lookup(:transaction_event_reservoir_size),
21
reservoir_size: Collector.AgentRun.lookup(:transaction_event_reservoir_size, 100),
22
22
events_seen: 0
23
23
},
24
24
events: PriorityQueue.new()
 
@@ -82,11 82,12 @@ defmodule NewRelic.Harvest.Collector.TransactionEvent.Harvester do
82
82
events
83
83
])
84
84
85
- log_harvest(length(events))
85
log_harvest(length(events), state.sampling.reservoir_size)
86
86
end
87
87
88
- def log_harvest(harvest_size) do
89
- NewRelic.report_metric({:supportability, TransactionEvent}, harvest_size: harvest_size)
88
def log_harvest(harvest_size, reservoir_size) do
89
NewRelic.report_metric({:supportability, "AnalyticEventData"}, harvest_size: harvest_size)
90
NewRelic.report_metric({:supportability, "AnalyticEventData"}, reservoir_size: reservoir_size)
90
91
NewRelic.log(:debug, "Completed Transaction Event harvest - size: #{harvest_size}")
91
92
end
changed lib/new_relic/harvest/collector/transaction_trace/harvester.ex
 
@@ -104,7 104,7 @@ defmodule NewRelic.Harvest.Collector.TransactionTrace.Harvester do
104
104
end
105
105
106
106
def log_harvest(harvest_size) do
107
- NewRelic.report_metric({:supportability, TransactionTrace}, harvest_size: harvest_size)
107
NewRelic.report_metric({:supportability, "TransactionTraceData"}, harvest_size: harvest_size)
108
108
NewRelic.log(:debug, "Completed Transaction Trace harvest - size: #{harvest_size}")
109
109
end
changed lib/new_relic/instrumented/httpoison.ex
 
@@ -30,7 30,7 @@ if Code.ensure_loaded?(HTTPoison) do
30
30
31
31
defp instrument(method, url, headers) do
32
32
NewRelic.set_span(:http, url: url, method: method, component: "HTTPoison")
33
- headers NewRelic.create_distributed_trace_payload(:http)
33
headers NewRelic.distributed_trace_headers(:http)
34
34
end
35
35
36
36
@trace {:get, category: :external}
changed lib/new_relic/span/event.ex
 
@@ -92,5 92,11 @@ defmodule NewRelic.Span.Event do
92
92
end
93
93
94
94
def merge_category_attributes(span, category_attributes),
95
- do: Map.merge(span, category_attributes)
95
do:
96
Map.merge(
97
span,
98
category_attributes,
99
# Don't overwrite existing span keys with custom values
100
fn _k, v1, _v2 -> v1 end
101
)
96
102
end
changed lib/new_relic/tracer.ex
 
@@ -40,7 40,7 @@ defmodule NewRelic.Tracer do
40
40
@trace {:request, category: :external}
41
41
def request(method, url, headers) do
42
42
NewRelic.set_span(:http, url: url, method: method, component: "HttpClient")
43
- headers NewRelic.create_distributed_trace_payload(:http)
43
headers NewRelic.distributed_trace_headers(:http)
44
44
HttpClient.request(method, url, headers)
45
45
end
46
46
end
changed lib/new_relic/tracer/report.ex
 
@@ -129,6 129,4 @@ defmodule NewRelic.Tracer.Report do
129
129
defp function_name({m, f}, i), do: "#{inspect(m)}.#{f}:#{i}"
130
130
defp function_name({m, f, a}, f), do: "#{inspect(m)}.#{f}/#{a}"
131
131
defp function_name({m, f, a}, i), do: "#{inspect(m)}.#{f}:#{i}/#{a}"
132
- defp function_name(f, f), do: "#{f}"
133
- defp function_name(_f, i), do: "#{i}"
134
132
end
changed lib/new_relic/transaction/complete.ex
 
@@ -164,17 164,27 @@ defmodule NewRelic.Transaction.Complete do
164
164
sampled: tx_attrs[:sampled],
165
165
priority: tx_attrs[:priority],
166
166
category: "generic",
167
- name: "Transaction Root Process #{inspect(pid)}",
167
name: "Transaction Root Process",
168
168
guid: DistributedTrace.generate_guid(pid: pid),
169
169
parent_id: tx_attrs[:parentSpanId],
170
170
timestamp: tx_attrs[:start_time],
171
171
duration: tx_attrs[:duration_s],
172
- entry_point: true
172
entry_point: true,
173
category_attributes:
174
%{
175
pid: inspect(pid)
176
}
177
|> maybe_add(:tracingVendors, tx_attrs[:tracingVendors])
178
|> maybe_add(:trustedParentId, tx_attrs[:trustedParentId])
173
179
}
174
180
| spans
175
181
]
176
182
end
177
183
184
def maybe_add(attrs, _key, nil), do: attrs
185
def maybe_add(attrs, _key, ""), do: attrs
186
def maybe_add(attrs, key, value), do: Map.put(attrs, key, value)
187
178
188
defp spawned_process_span_events(tx_attrs, process_spawns, process_names, process_exits) do
179
189
process_spawns
180
190
|> collect_process_segments(process_names, process_exits)
 
@@ -186,11 196,14 @@ defmodule NewRelic.Transaction.Complete do
186
196
sampled: tx_attrs[:sampled],
187
197
priority: tx_attrs[:priority],
188
198
category: "generic",
189
- name: "Process #{proc.name || proc.pid}",
199
name: proc.name || "Process",
190
200
guid: DistributedTrace.generate_guid(pid: proc.id),
191
201
parent_id: DistributedTrace.generate_guid(pid: proc.parent_id),
192
202
timestamp: proc[:start_time],
193
- duration: (proc[:end_time] - proc[:start_time]) / 1000
203
duration: (proc[:end_time] - proc[:start_time]) / 1000,
204
category_attributes: %{
205
pid: proc.pid
206
}
194
207
}
195
208
end)
196
209
end