Packages
appsignal
2.15.10
2.17.4
2.17.3
2.17.2
2.17.1
2.17.0
2.16.0
2.15.11
2.15.10
2.15.9
2.15.8
2.15.7
2.15.6
2.15.5
2.15.4
2.15.3
2.15.2
2.15.1
2.15.0
2.14.1
2.14.0
2.13.4
2.13.3
2.13.2
2.13.1
2.13.0
2.12.3
2.12.2
2.12.1
2.12.0
2.11.0
2.10.2
2.10.1
2.10.0
2.9.2
2.9.1
2.9.0
2.8.3
2.8.2
2.8.1
2.8.0
2.7.13
2.7.12
2.7.11
2.7.10
2.7.9
2.7.8
2.7.7
2.7.6
2.7.5
2.7.4
2.7.3
2.7.2
2.7.1
2.7.0
2.7.0-beta.1
2.6.1
2.6.0
2.5.3
2.5.2
2.5.1
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.1
2.3.0
2.2.19
2.2.18
2.2.17
2.2.16
2.2.15
2.2.14
2.2.13
2.2.12
retired
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.15
2.1.14
2.1.13
2.1.12
2.1.11
2.1.10
2.1.9
2.1.8
2.1.7
2.1.7-beta.1
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.8
2.0.7
2.0.6
2.0.6-beta.1
2.0.5
retired
2.0.4
retired
2.0.3
retired
2.0.2
retired
2.0.1
retired
2.0.0
retired
2.0.0-beta.11
2.0.0-beta.10
2.0.0-beta.9
2.0.0-beta.8
2.0.0-beta.7
2.0.0-beta.6
2.0.0-beta.5
2.0.0-beta.4
2.0.0-beta.3
2.0.0-beta.2
2.0.0-beta.1
2.0.0-alpha.7
2.0.0-alpha.6
2.0.0-alpha.5
2.0.0-alpha.4
2.0.0-alpha.3
2.0.0-alpha.2
2.0.0-alpha.1
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
1.13.0
1.13.0-beta.2
1.13.0-beta.1
1.12.1
1.12.0
1.12.0-beta.3
1.12.0-beta.2
1.12.0-beta.1
1.11.8
1.11.7
1.11.6
1.11.5
1.11.4
1.11.3
1.11.2
1.11.1
1.11.0
1.11.0-beta.1
1.10.13
1.10.12
1.10.11
1.10.10
1.10.9
1.10.8
1.10.7
1.10.6
1.10.5
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.4
1.9.3
1.9.2
1.9.1
1.9.1-beta.1
1.9.0
1.9.0-beta.1
1.9.0-alpha.1
1.8.2
1.8.1
1.8.1-beta.2
1.8.1-beta.1
1.8.0
1.7.2
1.7.1
1.7.0
1.7.0-beta.2
1.7.0-beta.1
1.7.0-alpha.4
1.7.0-alpha.3
1.7.0-alpha.2
1.7.0-alpha.1
1.6.7
1.6.6
1.6.6-beta.2
1.6.6-beta.1
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-beta.1
1.6.0-alpha.1
1.5.1
1.5.0
1.5.0-beta.2
1.5.0-beta.1
1.4.11-beta.1
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-alpha.1
1.3.6
1.3.6-beta.1
1.3.5
1.3.4
1.3.4-beta.1
1.3.3
1.3.2
1.3.1
1.3.0
1.3.0-beta.3
1.3.0-beta.2
1.3.0-beta.1
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.1
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.2
0.9.1
0.9.0
0.8.0
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Collects error and performance data from your Elixir applications and sends it to AppSignal
Current section
Files
Jump to
Current section
Files
lib/appsignal/probes/probes.ex
defmodule Appsignal.Probes do
@moduledoc false
use GenServer
require Logger
@integration_logger Application.compile_env(
:appsignal,
:appsignal_integration_logger,
Appsignal.IntegrationLogger
)
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def probes do
GenServer.call(__MODULE__, :probes)
end
def states do
GenServer.call(__MODULE__, :states)
end
def register(name, probe, state \\ nil) do
if genserver_running?() do
if is_function(probe) do
GenServer.cast(__MODULE__, {:register, {name, probe, state}})
:ok
else
Logger.debug(fn ->
"Trying to register probe #{name}. Ignoring probe since it's not a function."
end)
{:error, "Probe is not a function"}
end
else
{:error, "Probe genserver is not running"}
end
end
def unregister(name) do
GenServer.cast(__MODULE__, {:unregister, name})
:ok
end
def init([]) do
schedule_probes()
{:ok, {%{}, %{}}}
end
def handle_call(:probes, _from, {probes, states}) do
{:reply, probes, {probes, states}}
end
def handle_call(:states, _from, {probes, states}) do
{:reply, states, {probes, states}}
end
def handle_cast({:register, {name, probe, state}}, {probes, states}) do
if Map.has_key?(probes, name) do
Logger.debug(fn -> "A probe with name '#{name}' already exists. Overriding that one." end)
end
{:noreply,
{
Map.put(probes, name, probe),
Map.put(states, name, state)
}}
end
def handle_cast({:unregister, name}, {probes, states}) do
{:noreply,
{
Map.delete(probes, name),
Map.delete(states, name)
}}
end
def handle_info(:run_probes, {probes, states}) do
states =
if Appsignal.Config.minutely_probes_enabled?() do
@integration_logger.debug("Gathering minutely metrics with #{Enum.count(probes)} probes")
stream =
Task.async_stream(
probes,
fn {name, probe} ->
@integration_logger.debug("Gathering minutely metrics with '#{name}' probe")
state = Map.get(states, name)
try do
{name, call_probe(probe, state)}
rescue
e ->
"Error in minutely probe '#{name}': #{inspect(e)}"
|> @integration_logger.error()
{name, state}
end
end,
ordered: false,
timeout: 30000,
on_timeout: :kill_task
)
Enum.reduce(stream, states, fn result, states ->
case result do
{:ok, {name, state}} ->
Map.put(states, name, state)
{:exit, :timeout} ->
@integration_logger.error(
"A minutely probe took more than 30 seconds and was timed out."
)
states
end
end)
else
states
end
schedule_probes()
{:noreply, {probes, states}}
end
defp call_probe(probe, _state) when is_function(probe, 0) do
probe.()
nil
end
defp call_probe(probe, state) when is_function(probe, 1) do
probe.(state)
end
def child_spec(_) do
%{
id: Appsignal.Probes,
start: {Appsignal.Probes, :start_link, []}
}
end
defp genserver_running? do
pid = Process.whereis(__MODULE__)
!is_nil(pid) && Process.alive?(pid)
end
if Mix.env() in [:test, :test_no_nif] do
defp schedule_probes do
Process.send_after(self(), :run_probes, 10)
end
else
defp schedule_probes do
Process.send_after(self(), :run_probes, (60 - DateTime.utc_now().second) * 1000)
end
end
end