Packages
new_relic_agent
1.33.0
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/distributed_trace/backoff_sampler.ex
defmodule NewRelic.DistributedTrace.BackoffSampler do
use GenServer
alias NewRelic.Harvest.Collector.AgentRun
# This GenServer tracks the sampling rate across sampling periods,
# which is used to determine when to sample a Distributed Trace.
# State is stored in erlang `counters` which are super fast
@moduledoc false
def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
# Counter indexes
@size 5
@cycle_number 1
@sampled_true_count 2
@decided_count 3
@decided_count_last 4
@sampling_target 5
def init(:ok) do
NewRelic.sample_process()
:persistent_term.put({__MODULE__, :counter}, new(@size, []))
put(@sampling_target, AgentRun.lookup(:sampling_target) || 10)
trigger_next_cycle()
{:ok, %{}}
end
def sample? do
calculate(%{
cycle_number: get(@cycle_number),
sampled_true_count: get(@sampled_true_count),
decided_count: get(@decided_count),
decided_count_last: get(@decided_count_last),
sampling_target: get(@sampling_target)
})
end
def handle_info(:cycle, state) do
cycle()
trigger_next_cycle()
{:noreply, state}
end
def reset() do
put(@cycle_number, 0)
put(@decided_count_last, 0)
put(@decided_count, 0)
put(@sampled_true_count, 0)
end
def cycle() do
incr(@cycle_number)
put(@decided_count_last, get(@decided_count))
put(@decided_count, 0)
put(@sampled_true_count, 0)
end
defp calculate(state) do
sampled = do_sample?(state)
update_state(sampled)
sampled
end
def do_sample?(%{
cycle_number: 0,
sampled_true_count: sampled_true_count,
sampling_target: sampling_target
}) do
sampled_true_count < sampling_target
end
def do_sample?(%{
sampled_true_count: sampled_true_count,
sampling_target: sampling_target,
decided_count_last: decided_count_last
})
when sampled_true_count < sampling_target do
random(decided_count_last) < sampling_target
end
def do_sample?(%{
sampled_true_count: sampled_true_count,
sampling_target: sampling_target,
decided_count: decided_count
}) do
random(decided_count) <
:math.pow(sampling_target, sampling_target / sampled_true_count) -
:math.pow(sampling_target, 0.5)
end
def trigger_next_cycle() do
cycle_period = AgentRun.lookup(:sampling_target_period) || 60_000
Process.send_after(__MODULE__, :cycle, cycle_period)
end
defp update_state(false = _sampled?) do
incr(@decided_count)
end
defp update_state(true = _sampled?) do
incr(@decided_count)
incr(@sampled_true_count)
end
defp random(0), do: 0
defp random(n), do: :rand.uniform(n)
@compile {:inline, new: 2, incr: 1, put: 2, get: 1, pt: 0}
defp new(size, opts), do: :counters.new(size, opts)
defp incr(index), do: :counters.add(pt(), index, 1)
defp put(index, value), do: :counters.put(pt(), index, value)
defp get(index), do: :counters.get(pt(), index)
defp pt(), do: :persistent_term.get({__MODULE__, :counter})
end