Packages
new_relic_agent
1.18.2
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 ETS that lets us store efficently
# store and access arbitrary key->value pairs for all Transactions we are tracking
#
# It is backed by two ETS tables:
# 1) tracking all processes involved in a Transaction
# 2) collecting attributes stored on a Transaction
@moduledoc false
@ets_options [:named_table, :duplicate_bag, :public]
def new(table) do
:ets.new(collecting(table), @ets_options ++ [write_concurrency: true])
:ets.new(tracking(table), @ets_options ++ [read_concurrency: true, write_concurrency: true])
end
def track(table, pid) do
insert(
tracking(table),
{{pid, :tracking}, true}
)
end
def link(table, parent, child) do
root = find_root(parent, table)
insert(
tracking(table),
[
{{child, :tracking}, true},
{{child, :child_of}, root},
{{root, :root_of}, child}
]
)
end
def root(table, pid) do
find_root(pid, table)
end
def add(table, pid, attrs) when is_list(attrs) do
insert(
collecting(table),
Enum.map(attrs, fn {key, value} -> {pid, {key, value}} end)
)
end
def incr(table, pid, attrs) when is_list(attrs) do
insert(
collecting(table),
Enum.map(attrs, fn {key, value} -> {pid, {key, {:counter, value}}} end)
)
end
def tracking?(table, pid) do
member?(
tracking(table),
{pid, :tracking}
)
end
def collect(table, pid) do
pid
|> with_children(table)
|> find_attributes(table)
|> Enum.reduce(%{}, &collect_attr/2)
end
def untrack(table, pid) do
pid
|> find_root(table)
|> with_children(table)
|> Enum.each(fn pid ->
delete(tracking(table), {pid, :tracking})
end)
end
def purge(table, pid) do
pid
|> find_root(table)
|> with_children(table)
|> Enum.each(fn pid ->
delete(collecting(table), pid)
delete(tracking(table), {pid, :tracking})
delete(tracking(table), {pid, :child_of})
delete(tracking(table), {pid, :root_of})
end)
end
defp find_root(pid, table) do
lookup(
tracking(table),
{pid, :child_of}
)
|> case do
[{_, root} | _] -> root
[] -> pid
end
end
defp with_children(pid, table) do
[pid | find_children(table, pid)]
end
defp find_children(table, root_pid) do
lookup(
tracking(table),
{root_pid, :root_of}
)
|> Enum.map(fn {_, child} -> child end)
end
def find_attributes(pids, table) do
Enum.flat_map(pids, fn pid ->
take(
collecting(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 collecting(table), do: Module.concat(table, Collecting)
defp tracking(table), do: Module.concat(table, Tracking)
defp lookup(table, term) do
:ets.lookup(table, term)
rescue
ArgumentError -> []
end
defp take(table, term) do
:ets.take(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