changed
CHANGELOG.md
|
@@ -1,6 1,13 @@
|
1
1
|
## CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
### `v1.13.0`
|
5
|
|
6
|
Features
|
7
|
|
8
|
* `OTP 21 ` has been required for a while, and now the agent will enforce this version requirement [#151](https://github.com/newrelic/elixir_agent/pull/151)
|
9
|
* Truncate super large nested attribute structure [#153](https://github.com/newrelic/elixir_agent/pull/153)
|
10
|
|
4
11
|
### `v1.12.0`
|
5
12
|
|
6
13
|
Features
|
changed
README.md
|
@@ -19,6 19,10 @@ We'd love to get your contributions to improve the elixir agent! Keep in mind wh
|
19
19
|
|
20
20
|
Install the [Hex package](https://hex.pm/packages/new_relic_agent)
|
21
21
|
|
22
|
Requirements:
|
23
|
* Erlang/OTP 21
|
24
|
* Elixir 1.8
|
25
|
|
22
26
|
```elixir
|
23
27
|
defp deps do
|
24
28
|
[
|
|
@@ -72,9 76,10 @@ defmodule MyPlug do
|
72
76
|
end
|
73
77
|
```
|
74
78
|
|
75
|
- #### Function Tracing
|
79
|
#### Tracing
|
80
|
|
81
|
* `NewRelic.Tracer` enables detailed Function tracing. Annotate a function and it'll show up as a span in Transaction Traces / Distributed Traces, and we'll collect aggregate stats about it. Install it by adding `use NewRelic.Tracer` to any module, and annotating any function with `@trace` module attribute
|
76
82
|
|
77
|
- * `NewRelic.Tracer` enables detailed Function Tracing. Annotate a function and it'll show up as a span in Transaction Traces / Distributed Traces, and we'll collect aggregate stats about it. Install it by adding `use NewRelic.Tracer` to any module, and annotating any function with `@trace` module attribute
|
78
83
|
|
79
84
|
```elixir
|
80
85
|
defmodule MyModule do
|
|
@@ -87,6 92,21 @@ defmodule MyModule do
|
87
92
|
end
|
88
93
|
```
|
89
94
|
|
95
|
* `NewRelic.Tracer` also enables detailed External request tracing. A little more instrumentation is required to pass the trace context forward with Distributed Tracing.
|
96
|
|
97
|
```elixir
|
98
|
defmodule MyExternalService do
|
99
|
use NewRelic.Tracer
|
100
|
|
101
|
@trace {:request, category: :external}
|
102
|
def request(method, url, headers) do
|
103
|
NewRelic.set_span(:http, url: url, method: method, component: "HttpClient")
|
104
|
headers NewRelic.create_distributed_trace_payload(:http)
|
105
|
HttpClient.request(method, url, headers)
|
106
|
end
|
107
|
end
|
108
|
```
|
109
|
|
90
110
|
#### `Mix.Task`
|
91
111
|
|
92
112
|
To enable the agent during a `Mix.Task`, you simply need to start and stop it.
|
changed
VERSION
|
@@ -1 1 @@
|
1
|
- 1.12.0
|
1
|
1.13.0
|
changed
hex_metadata.config
|
@@ -1,7 1,7 @@
|
1
1
|
{<<"app">>,<<"new_relic_agent">>}.
|
2
2
|
{<<"build_tools">>,[<<"mix">>]}.
|
3
3
|
{<<"description">>,<<"New Relic's Open-Source Elixir Agent">>}.
|
4
|
- {<<"elixir">>,<<"~> 1.7">>}.
|
4
|
{<<"elixir">>,<<"~> 1.8">>}.
|
5
5
|
{<<"files">>,
|
6
6
|
[<<"lib">>,<<"lib/new_relic">>,<<"lib/new_relic/transaction.ex">>,
|
7
7
|
<<"lib/new_relic/tracer">>,<<"lib/new_relic/tracer/macro.ex">>,
|
|
@@ -32,7 32,8 @@
|
32
32
|
<<"lib/new_relic/aggregate/supervisor.ex">>,
|
33
33
|
<<"lib/new_relic/aggregate/reporter.ex">>,
|
34
34
|
<<"lib/new_relic/aggregate/aggregate.ex">>,<<"lib/new_relic/config.ex">>,
|
35
|
- <<"lib/new_relic/distributed_trace.ex">>,<<"lib/new_relic/harvest">>,
|
35
|
<<"lib/new_relic/distributed_trace.ex">>,
|
36
|
<<"lib/new_relic/always_on_supervisor.ex">>,<<"lib/new_relic/harvest">>,
|
36
37
|
<<"lib/new_relic/harvest/supervisor.ex">>,
|
37
38
|
<<"lib/new_relic/harvest/collector">>,
|
38
39
|
<<"lib/new_relic/harvest/collector/supervisor.ex">>,
|
|
@@ -72,9 73,10 @@
|
72
73
|
<<"lib/new_relic/error/reporter.ex">>,
|
73
74
|
<<"lib/new_relic/error/logger_handler.ex">>,
|
74
75
|
<<"lib/new_relic/error/event.ex">>,<<"lib/new_relic/error/trace.ex">>,
|
75
|
- <<"lib/new_relic/error/error_logger_handler.ex">>,<<"lib/new_relic.ex">>,
|
76
|
- <<"priv">>,<<"priv/cacert.pem">>,<<"mix.exs">>,<<"README.md">>,
|
77
|
- <<"CHANGELOG.md">>,<<"VERSION">>]}.
|
76
|
<<"lib/new_relic/error/error_logger_handler.ex">>,
|
77
|
<<"lib/new_relic/enabled_supervisor.ex">>,<<"lib/new_relic.ex">>,<<"priv">>,
|
78
|
<<"priv/cacert.pem">>,<<"mix.exs">>,<<"README.md">>,<<"CHANGELOG.md">>,
|
79
|
<<"VERSION">>]}.
|
78
80
|
{<<"licenses">>,[<<"Apache 2.0">>]}.
|
79
81
|
{<<"links">>,[{<<"GitHub">>,<<"https://github.com/newrelic/elixir_agent">>}]}.
|
80
82
|
{<<"name">>,<<"new_relic_agent">>}.
|
|
@@ -94,4 96,4 @@
|
94
96
|
{<<"optional">>,false},
|
95
97
|
{<<"repository">>,<<"hexpm">>},
|
96
98
|
{<<"requirement">>,<<"~> 1.1">>}]]}.
|
97
|
- {<<"version">>,<<"1.12.0">>}.
|
99
|
{<<"version">>,<<"1.13.0">>}.
|
changed
lib/new_relic.ex
|
@@ -9,6 9,9 @@ defmodule NewRelic do
|
9
9
|
The first segment will be treated as the Transaction namespace,
|
10
10
|
and commonly contains the name of the framework.
|
11
11
|
|
12
|
**Notes:**
|
13
|
* At least 2 segments are required to light up the Transactions UI in APM
|
14
|
|
12
15
|
In the following example, you will see `/custom/transaction/name`
|
13
16
|
in the Transaction list.
|
14
17
|
|
|
@@ -19,11 22,30 @@ defmodule NewRelic do
|
19
22
|
defdelegate set_transaction_name(name), to: NewRelic.Transaction.Reporter
|
20
23
|
|
21
24
|
@doc """
|
22
|
- Report a custom attribute on the current transaction
|
25
|
Report custom attributes on the current Transaction
|
26
|
|
27
|
Reporting nested data structures is supported by auto-flattening them
|
28
|
into a list of key-value pairs.
|
23
29
|
|
24
30
|
```elixir
|
25
31
|
NewRelic.add_attributes(foo: "bar")
|
32
|
# "foo" => "bar"
|
33
|
|
34
|
NewRelic.add_attributes(map: %{foo: "bar", baz: "qux"})
|
35
|
# "map.foo" => "bar"
|
36
|
# "map.baz" => "qux"
|
37
|
# "map.size" => 2
|
38
|
|
39
|
NewRelic.add_attributes(list: ["a", "b", "c"])
|
40
|
# "list.0" => "a"
|
41
|
# "list.1" => "b"
|
42
|
# "list.2" => "c"
|
43
|
# "list.length" => 3
|
26
44
|
```
|
45
|
|
46
|
**Notes:**
|
47
|
* Nested Lists and Maps are truncated at 10 items since there are a limited number
|
48
|
of attributes that can be reported on Transaction events
|
27
49
|
"""
|
28
50
|
defdelegate add_attributes(custom_attributes), to: NewRelic.Transaction.Reporter
|
added
lib/new_relic/always_on_supervisor.ex
|
@@ -0,0 1,20 @@
|
1
|
defmodule NewRelic.AlwaysOnSupervisor do
|
2
|
use Supervisor
|
3
|
|
4
|
@moduledoc false
|
5
|
|
6
|
def start_link do
|
7
|
Supervisor.start_link(__MODULE__, [])
|
8
|
end
|
9
|
|
10
|
def init(_) do
|
11
|
children = [
|
12
|
worker(NewRelic.Harvest.Collector.AgentRun, []),
|
13
|
worker(NewRelic.Harvest.Collector.HarvesterStore, []),
|
14
|
supervisor(NewRelic.DistributedTrace.Supervisor, []),
|
15
|
supervisor(NewRelic.Transaction.Supervisor, [])
|
16
|
]
|
17
|
|
18
|
supervise(children, strategy: :one_for_one)
|
19
|
end
|
20
|
end
|
changed
lib/new_relic/application.ex
|
@@ -10,12 10,8 @@ defmodule NewRelic.Application do
|
10
10
|
|
11
11
|
children = [
|
12
12
|
worker(NewRelic.Logger, []),
|
13
|
- supervisor(NewRelic.Harvest.Supervisor, []),
|
14
|
- supervisor(NewRelic.Sampler.Supervisor, []),
|
15
|
- supervisor(NewRelic.Error.Supervisor, []),
|
16
|
- supervisor(NewRelic.Transaction.Supervisor, []),
|
17
|
- supervisor(NewRelic.DistributedTrace.Supervisor, []),
|
18
|
- supervisor(NewRelic.Aggregate.Supervisor, []),
|
13
|
supervisor(NewRelic.AlwaysOnSupervisor, []),
|
14
|
supervisor(NewRelic.EnabledSupervisor, [[enabled: NewRelic.Config.enabled?()]]),
|
19
15
|
worker(NewRelic.GracefulShutdown, [], shutdown: 30_000)
|
20
16
|
]
|
added
lib/new_relic/enabled_supervisor.ex
|
@@ -0,0 1,27 @@
|
1
|
defmodule NewRelic.EnabledSupervisor do
|
2
|
use Supervisor
|
3
|
|
4
|
# This Supervisor starts processes that we
|
5
|
# only start if the agent is enabled
|
6
|
|
7
|
@moduledoc false
|
8
|
|
9
|
def start_link(enabled: enabled) do
|
10
|
Supervisor.start_link(__MODULE__, enabled: enabled)
|
11
|
end
|
12
|
|
13
|
def init(enabled: false) do
|
14
|
:ignore
|
15
|
end
|
16
|
|
17
|
def init(enabled: true) do
|
18
|
children = [
|
19
|
supervisor(NewRelic.Harvest.Supervisor, []),
|
20
|
supervisor(NewRelic.Sampler.Supervisor, []),
|
21
|
supervisor(NewRelic.Error.Supervisor, []),
|
22
|
supervisor(NewRelic.Aggregate.Supervisor, [])
|
23
|
]
|
24
|
|
25
|
supervise(children, strategy: :one_for_one)
|
26
|
end
|
27
|
end
|
changed
lib/new_relic/harvest/collector/agent_run.ex
|
@@ -38,9 38,6 @@ defmodule NewRelic.Harvest.Collector.AgentRun do
|
38
38
|
|
39
39
|
{:error, _reason} ->
|
40
40
|
{:noreply, %{status: :error_during_preconnect}}
|
41
|
-
|
42
|
- {:failed_connect, _reason} ->
|
43
|
- {:noreply, %{status: :failed_to_preconnect}}
|
44
41
|
end
|
45
42
|
end
|
changed
lib/new_relic/harvest/collector/metric_data.ex
|
@@ -136,6 136,38 @@ defmodule NewRelic.Harvest.Collector.MetricData do
|
136
136
|
}
|
137
137
|
]
|
138
138
|
|
139
|
def transform({:external, url, component, method}, duration_s: duration_s) do
|
140
|
host = URI.parse(url).host
|
141
|
method = method |> to_string() |> String.upcase()
|
142
|
|
143
|
[
|
144
|
%Metric{
|
145
|
name: :"External/all",
|
146
|
call_count: 1,
|
147
|
total_call_time: duration_s,
|
148
|
total_exclusive_time: duration_s,
|
149
|
min_call_time: duration_s,
|
150
|
max_call_time: duration_s
|
151
|
},
|
152
|
%Metric{
|
153
|
name: join(["External", host, "all"]),
|
154
|
call_count: 1,
|
155
|
total_call_time: duration_s,
|
156
|
total_exclusive_time: duration_s,
|
157
|
min_call_time: duration_s,
|
158
|
max_call_time: duration_s
|
159
|
},
|
160
|
%Metric{
|
161
|
name: join(["External", host, component, method]),
|
162
|
call_count: 1,
|
163
|
total_call_time: duration_s,
|
164
|
total_exclusive_time: duration_s,
|
165
|
min_call_time: duration_s,
|
166
|
max_call_time: duration_s
|
167
|
}
|
168
|
]
|
169
|
end
|
170
|
|
139
171
|
def transform({:external, name}, duration_s: duration_s),
|
140
172
|
do: [
|
141
173
|
%Metric{
|
changed
lib/new_relic/harvest/collector/protocol.ex
|
@@ -79,7 79,8 @@ defmodule NewRelic.Harvest.Collector.Protocol do
|
79
79
|
{:error, reason}
|
80
80
|
end
|
81
81
|
|
82
|
- defp parse_collector_response({:error, code}), do: code
|
82
|
defp parse_collector_response({:error, code}) when is_integer(code), do: code
|
83
|
defp parse_collector_response({:error, reason}), do: {:error, reason}
|
83
84
|
defp parse_collector_response({:ok, %{"return_value" => return_value}}), do: return_value
|
84
85
|
|
85
86
|
defp parse_collector_response({:ok, %{"exception" => exception_value}}),
|
changed
lib/new_relic/harvest/collector/supervisor.ex
|
@@ -11,7 11,6 @@ defmodule NewRelic.Harvest.Collector.Supervisor do
|
11
11
|
|
12
12
|
def init(_) do
|
13
13
|
children = [
|
14
|
- worker(Collector.AgentRun, []),
|
15
14
|
data_supervisor(Collector.Metric, :data_report_period),
|
16
15
|
data_supervisor(Collector.TransactionTrace, :data_report_period),
|
17
16
|
data_supervisor(Collector.ErrorTrace, :data_report_period),
|
changed
lib/new_relic/harvest/supervisor.ex
|
@@ -20,7 20,6 @@ defmodule NewRelic.Harvest.Supervisor do
|
20
20
|
|
21
21
|
def init(_) do
|
22
22
|
children = [
|
23
|
- worker(Collector.HarvesterStore, []),
|
24
23
|
supervisor(Task.Supervisor, [[name: Collector.TaskSupervisor]]),
|
25
24
|
supervisor(Collector.Supervisor, [])
|
26
25
|
]
|
changed
lib/new_relic/init.ex
|
@@ -2,9 2,19 @@ defmodule NewRelic.Init do
|
2
2
|
@moduledoc false
|
3
3
|
|
4
4
|
def run() do
|
5
|
verify_erlang_otp_version()
|
5
6
|
init_collector_host()
|
6
7
|
end
|
7
8
|
|
9
|
@erlang_version_requirement ">= 21.0.0"
|
10
|
def verify_erlang_otp_version() do
|
11
|
if Version.match?(System.otp_release() <> ".0.0", @erlang_version_requirement) do
|
12
|
:ok
|
13
|
else
|
14
|
raise "Erlang/OTP 21 required"
|
15
|
end
|
16
|
end
|
17
|
|
8
18
|
def init_collector_host() do
|
9
19
|
Application.put_env(:new_relic_agent, :collector_host, determine_collector_host())
|
10
20
|
end
|
changed
lib/new_relic/tracer.ex
|
@@ -29,15 29,19 @@ defmodule NewRelic.Tracer do
|
29
29
|
|
30
30
|
#### Categories
|
31
31
|
|
32
|
- To categorize External Service calls, use this syntax:
|
32
|
To categorize External Service calls you must give the trace annotation a category.
|
33
|
|
34
|
You may also call `NewRelic.set_span` to provide better naming for metrics & spans, and additonally annotate the outgoing HTTP headers with the Distributed Tracing context to track calls across services.
|
33
35
|
|
34
36
|
```elixir
|
35
37
|
defmodule MyExternalService do
|
36
38
|
use NewRelic.Tracer
|
37
39
|
|
38
|
- @trace {:query, category: :external}
|
39
|
- def query(args) do
|
40
|
- # Make the call
|
40
|
@trace {:request, category: :external}
|
41
|
def request(method, url, headers) do
|
42
|
NewRelic.set_span(:http, url: url, method: method, component: "HttpClient")
|
43
|
headers NewRelic.create_distributed_trace_payload(:http)
|
44
|
HttpClient.request(method, url, headers)
|
41
45
|
end
|
42
46
|
end
|
43
47
|
```
|
|
@@ -47,14 51,14 @@ defmodule NewRelic.Tracer do
|
47
51
|
* Add custom attributes to Transaction events:
|
48
52
|
- `external_call_count`
|
49
53
|
- `external_duration_ms`
|
50
|
- - `external.MyExternalService.query/0.call_count`
|
51
|
- - `external.MyExternalService.query/0.duration_ms`
|
54
|
- `external.MyExternalService.query.call_count`
|
55
|
- `external.MyExternalService.query.duration_ms`
|
52
56
|
|
53
57
|
Transactions that call the traced `ExternalService` functions will contain `external_call_count` attribute
|
54
58
|
|
55
59
|
```elixir
|
56
60
|
get "/endpoint" do
|
57
|
- ExternalService.query(2)
|
61
|
ExternalService.request(:get, url, headers)
|
58
62
|
send_resp(conn, 200, "ok")
|
59
63
|
end
|
60
64
|
```
|
changed
lib/new_relic/tracer/report.ex
|
@@ -78,6 78,10 @@ defmodule NewRelic.Tracer.Report do
|
78
78
|
duration_s = duration_ms / 1000
|
79
79
|
arity = length(arguments)
|
80
80
|
args = inspect_args(arguments)
|
81
|
span_attrs = NewRelic.DistributedTrace.get_span_attrs()
|
82
|
|
83
|
function_name = function_name({module, function}, name)
|
84
|
function_arity_name = function_name({module, function, arity}, name)
|
81
85
|
|
82
86
|
Transaction.Reporter.add_trace_segment(%{
|
83
87
|
module: module,
|
|
@@ -96,23 100,23 @@ defmodule NewRelic.Tracer.Report do
|
96
100
|
NewRelic.report_span(
|
97
101
|
timestamp_ms: System.convert_time_unit(start_time, :native, :millisecond),
|
98
102
|
duration_s: duration_s,
|
99
|
- name: function_name({module, function, arity}, name),
|
103
|
name: function_arity_name,
|
100
104
|
edge: [span: id, parent: parent_id],
|
101
105
|
category: "http",
|
102
|
- attributes: Map.put(NewRelic.DistributedTrace.get_span_attrs(), :args, args)
|
106
|
attributes: Map.put(span_attrs, :args, args)
|
103
107
|
)
|
104
108
|
|
105
109
|
NewRelic.incr_attributes(
|
106
110
|
external_call_count: 1,
|
107
111
|
external_duration_ms: duration_ms,
|
108
|
- "external.#{function_name({module, function}, name)}.call_count": 1,
|
109
|
- "external.#{function_name({module, function}, name)}.duration_ms": duration_ms
|
112
|
"external.#{function_name}.call_count": 1,
|
113
|
"external.#{function_name}.duration_ms": duration_ms
|
110
114
|
)
|
111
115
|
|
112
116
|
NewRelic.report_aggregate(
|
113
117
|
%{
|
114
118
|
name: :FunctionTrace,
|
115
|
- mfa: function_name({module, function, arity}, name),
|
119
|
mfa: function_arity_name,
|
116
120
|
metric_category: :external
|
117
121
|
},
|
118
122
|
%{duration_ms: duration_ms, call_count: 1}
|
|
@@ -120,10 124,13 @@ defmodule NewRelic.Tracer.Report do
|
120
124
|
|
121
125
|
Transaction.Reporter.track_metric({:external, duration_s})
|
122
126
|
|
123
|
- NewRelic.report_metric(
|
124
|
- {:external, function_name({module, function}, name)},
|
125
|
- duration_s: duration_s
|
126
|
- )
|
127
|
case span_attrs do
|
128
|
%{url: url, component: component, method: method} ->
|
129
|
NewRelic.report_metric({:external, url, component, method}, duration_s: duration_s)
|
130
|
|
131
|
_ ->
|
132
|
NewRelic.report_metric({:external, function_name}, duration_s: duration_s)
|
133
|
end
|
127
134
|
end
|
128
135
|
|
129
136
|
def call(
|
|
@@ -168,11 175,11 @@ defmodule NewRelic.Tracer.Report do
|
168
175
|
)
|
169
176
|
end
|
170
177
|
|
171
|
- def inspect_args(arguments) do
|
178
|
defp inspect_args(arguments) do
|
172
179
|
inspect(arguments, charlists: :as_lists, limit: 20, printable_limit: 100)
|
173
180
|
end
|
174
181
|
|
175
|
- def duration_ms(start_time_mono, end_time_mono),
|
182
|
defp duration_ms(start_time_mono, end_time_mono),
|
176
183
|
do: System.convert_time_unit(end_time_mono - start_time_mono, :native, :millisecond)
|
177
184
|
|
178
185
|
defp function_name({m, f}, f), do: "#{inspect(m)}.#{f}"
|
changed
lib/new_relic/util.ex
|
@@ -33,13 33,19 @@ defmodule NewRelic.Util do
|
33
33
|
Enum.flat_map(attrs, &deep_flatten/1)
|
34
34
|
end
|
35
35
|
|
36
|
- def deep_flatten({key, value}) when is_list(value) do
|
37
|
- Enum.with_index(value)
|
36
|
def deep_flatten({key, list_value}) when is_list(list_value) do
|
37
|
list_value
|
38
|
|> Enum.slice(0..9)
|
39
|
|> Enum.with_index()
|
38
40
|
|> Enum.flat_map(fn {v, index} -> deep_flatten({"#{key}.#{index}", v}) end)
|
41
|
|> Enum.concat([{"#{key}.length", length(list_value)}])
|
39
42
|
end
|
40
43
|
|
41
|
- def deep_flatten({key, value}) when is_map(value) do
|
42
|
- Enum.flat_map(value, fn {k, v} -> deep_flatten({"#{key}.#{k}", v}) end)
|
44
|
def deep_flatten({key, map_value}) when is_map(map_value) do
|
45
|
map_value
|
46
|
|> Enum.slice(0..9)
|
47
|
|> Enum.flat_map(fn {k, v} -> deep_flatten({"#{key}.#{k}", v}) end)
|
48
|
|> Enum.concat([{"#{key}.size", map_size(map_value)}])
|
43
49
|
end
|
44
50
|
|
45
51
|
def deep_flatten({key, value}) do
|
changed
lib/new_relic/util/http.ex
|
@@ -9,7 9,7 @@ defmodule NewRelic.Util.HTTP do
|
9
9
|
%{host: host} = URI.parse(url)
|
10
10
|
|
11
11
|
with {:ok, {{_, status_code, _}, _headers, body}} <-
|
12
|
- :httpc.request(:post, request, ssl_options(host), []) do
|
12
|
:httpc.request(:post, request, http_options(host), []) do
|
13
13
|
{:ok, %{status_code: status_code, body: to_string(body)}}
|
14
14
|
end
|
15
15
|
end
|
|
@@ -21,8 21,9 @@ defmodule NewRelic.Util.HTTP do
|
21
21
|
Certs are pulled from Mozilla exactly as Hex does:
|
22
22
|
https://github.com/hexpm/hex/blob/master/README.md#bundled-ca-certs
|
23
23
|
"""
|
24
|
- def ssl_options(host) do
|
24
|
def http_options(host) do
|
25
25
|
[
|
26
|
connect_timeout: 1000,
|
26
27
|
ssl: [
|
27
28
|
verify: :verify_peer,
|
28
29
|
cacertfile: Application.app_dir(:new_relic_agent, "priv/cacert.pem"),
|
changed
mix.exs
|
@@ -6,7 6,7 @@ defmodule NewRelic.Mixfile do
|
6
6
|
app: :new_relic_agent,
|
7
7
|
description: "New Relic's Open-Source Elixir Agent",
|
8
8
|
version: agent_version(),
|
9
|
- elixir: "~> 1.7",
|
9
|
elixir: "~> 1.8",
|
10
10
|
build_embedded: Mix.env() == :prod,
|
11
11
|
start_permanent: Mix.env() == :prod,
|
12
12
|
name: "New Relic Elixir Agent",
|