Packages
new_relic_agent
1.25.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
@moduledoc false
def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
NewRelic.sample_process()
trigger_next_cycle()
{:ok, init_state()}
end
def init_state() do
%{
sampling_target: AgentRun.lookup(:sampling_target) || 10,
cycle_number: 0,
sampled_true_count: 0,
decided_count: 0,
decided_count_last: 0
}
end
def sample?, do: GenServer.call(__MODULE__, :sample?)
def handle_call(:sample?, _from, state) do
{sampled, state} = calculate(state)
{:reply, sampled, state}
end
def handle_info(:cycle, state) do
trigger_next_cycle()
{:noreply, cycle(state)}
end
def handle_info(:reset, _state) do
{:noreply, init_state()}
end
def cycle(state) do
%{
state
| cycle_number: state.cycle_number + 1,
sampled_true_count: 0,
decided_count: 0,
decided_count_last: state.decided_count
}
end
def calculate(state) do
sampled = do_sample?(state)
state = update_state(sampled, state)
{sampled, state}
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(self(), :cycle, cycle_period)
end
def update_state(false = _sampled?, state) do
%{state | decided_count: state.decided_count + 1}
end
def update_state(true = _sampled?, state) do
%{
state
| decided_count: state.decided_count + 1,
sampled_true_count: state.sampled_true_count + 1
}
end
def random(0), do: 0
def random(n), do: :rand.uniform(n)
end