Packages
new_relic_agent
1.0.4
1.40.3
1.40.2
1.40.1
1.40.0
1.39.0
1.38.0
1.37.0
1.36.0
1.35.0
1.34.0
1.33.0
1.32.0
1.31.1
1.31.0
1.30.0
1.29.0
1.28.0
1.27.8
1.27.7
1.27.6
1.27.5
1.27.4
1.27.3
1.27.2
1.27.1
1.27.0
1.26.0
1.25.3
1.25.2
1.25.1
1.25.0
1.24.5
1.24.4
1.24.3
1.24.2
1.24.1
1.24.0
1.24.0-rc.10
1.24.0-rc.9
1.24.0-rc.8
1.24.0-rc.7
1.23.6
1.23.5
1.23.4
1.23.3
1.23.2
1.23.1
1.23.0
1.23.0-rc.6
1.23.0-rc.5
1.23.0-rc.4
1.23.0-rc.3
1.23.0-rc.2
1.23.0-rc.1
1.22.6
1.22.5
1.22.4
1.22.3
1.22.2
1.22.1
1.22.0
1.21.2
1.21.1
1.21.0
1.21.0-rc.3
1.21.0-rc.1
1.20.0
1.20.0-rc.1
1.19.7
1.19.6
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.18.0-rc.5
1.18.0-rc.4
1.18.0-rc.2
1.18.0-rc.1
1.17.1
1.17.0
1.17.0-rc.4
1.17.0-rc.3
1.17.0-rc.2
1.17.0-rc.1
1.17.0-rc.0
1.16.7
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.16.0-rc.2
1.16.0-rc.1
1.16.0-rc.0
1.15.0
1.15.0-rc.3
1.15.0-rc.2
1.15.0-rc.1
1.14.0
1.13.1
1.13.0
1.12.0
1.11.0
1.10.2
1.10.1
1.10.0
1.9.12
1.9.11
1.9.10
1.9.9
1.9.8
1.9.7
1.9.6
1.9.5
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.0
1.6.2
1.6.1
1.6.0
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
New Relic's Open-Source Elixir Agent
Current section
Files
Jump to
Current section
Files
lib/new_relic/util/attr_store.ex
defmodule NewRelic.Util.AttrStore do
# This is an abstraction around an ETS table that lets us store efficently
# store and access arbitrary key->value pairs for all Transactions we are tracking
@moduledoc false
def new(table) do
:ets.new(table, [
:named_table,
:duplicate_bag,
:public,
read_concurrency: true,
write_concurrency: true
])
end
def track(table, pid) do
insert(table, {{pid, :tracking}, true})
end
def link(table, parent, child, attrs \\ []) do
root = find_root(table, parent)
extras = Enum.map(attrs, fn {key, value} -> {child, {key, value}} end)
insert(table, [
{{child, :tracking}, true},
{{child, :child_of}, root},
{{root, :root_of}, child} | extras
])
end
def add(table, pid, attrs)
when is_list(attrs) do
items = Enum.map(attrs, fn {key, value} -> {pid, {key, value}} end)
insert(table, items)
end
def incr(table, pid, attrs)
when is_list(attrs) do
items = Enum.map(attrs, fn {key, value} -> {pid, {key, {:counter, value}}} end)
insert(table, items)
end
def tracking?(table, pid) do
member?(table, {pid, :tracking})
end
def collect(table, pid) do
pids = [pid | find_children(table, pid)]
table
|> find_attributes(pids)
|> Enum.reduce(%{}, &collect_attr/2)
end
def untrack(table, pid) do
delete(table, {pid, :tracking})
end
def purge(table, pid) do
[pid | find_children(table, pid)]
|> Enum.each(fn pid ->
delete(table, pid)
delete(table, {pid, :tracking})
delete(table, {pid, :child_of})
delete(table, {pid, :root_of})
end)
end
def find_root(table, pid) do
lookup(table, {pid, :child_of})
|> case do
[{_, root} | _] -> root
[] -> pid
end
end
def find_children(table, root_pid) do
lookup(table, {root_pid, :root_of})
|> Enum.map(fn {_, child} -> child end)
end
def find_attributes(table, pids) do
Enum.flat_map(pids, fn pid ->
lookup(table, pid)
end)
end
defp collect_attr({_pid, {k, {:list, item}}}, acc), do: Map.update(acc, k, [item], &[item | &1])
defp collect_attr({_pid, {k, {:counter, n}}}, acc), do: Map.update(acc, k, n, &(&1 + n))
defp collect_attr({_pid, {k, v}}, acc), do: Map.put(acc, k, v)
defp lookup(table, term) do
:ets.lookup(table, term)
rescue
ArgumentError -> []
end
defp insert(table, term) do
:ets.insert(table, term)
rescue
ArgumentError -> false
end
defp delete(table, term) do
:ets.delete(table, term)
rescue
ArgumentError -> false
end
defp member?(table, term) do
:ets.member(table, term)
rescue
ArgumentError -> false
end
end