Current section

Files

Jump to
kvasir_agent_server lib kvasir agent_server system_monitor.ex
Raw

lib/kvasir/agent_server/system_monitor.ex

defmodule Kvasir.AgentServer.SystemMonitor do
alias Kvasir.AgentServer.Metrics
use GenServer
@interval 1
@refresh 1_000 * @interval
@agent_data ~w(id agent partition)a
@sup Kvasir.AgentServer.Client.ConnectionManager
require Logger
@spec register(String.t() | charlist, Kvasir.AgentServer.agent()) :: :ok
def register(path, agent) do
if pid = Process.whereis(__MODULE__),
do: send(pid, {:register_agent, path, Map.take(agent, @agent_data)})
:ok
end
@spec start :: DynamicSupervisor.on_start_child()
def start do
Logger.info("Kvasir AgentServer: Starting system monitor.")
Application.put_all_env(
[
os_mon: [
disk_space_check_interval: @interval,
disk_almost_full_threshold: 0.85,
start_cpu_sup: false,
start_disksup: true,
start_memsup: false,
start_os_sup: false
]
],
persistent: true
)
:application.ensure_all_started(:os_mon)
DynamicSupervisor.start_child(@sup, __MODULE__)
end
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end
@impl GenServer
def init(_) do
Logger.info("Kvasir AgentServer: Initializing system monitor.")
send(self(), :check_disks)
paths =
:disksup.get_disk_data()
|> Enum.map(&elem(&1, 0))
|> Enum.sort_by(&(-Enum.count(&1)))
Logger.info(fn ->
"Kvasir AgentServer: System Monitor Detected Disks: #{inspect(:disksup.get_disk_data())}"
end)
metrics = system_metrics(System.get_env("STATSD_URL"))
{:ok, %{agents: %{}, paths: paths, metrics: metrics}}
end
@impl GenServer
def handle_info(:check_disks, state = %{agents: agents, metrics: metrics}) do
Enum.map(:disksup.get_disk_data(), fn {path, _size, used} ->
if a = agents[path], do: Enum.each(a, &metrics.(&1, path, used))
end)
Process.send_after(self(), :check_disks, @refresh)
{:noreply, state}
end
def handle_info({:register_agent, path, agent}, state = %{agents: agents, paths: paths}) do
full = Path.expand(path)
index = Enum.find(paths, &String.starts_with?(full, to_string(&1)))
updated = Map.update(agents, index, [agent], &[agent | &1])
Logger.info("Kvasir AgentServer: Add #{inspect(agent)} to #{inspect(index)} monitor.")
{:noreply, %{state | agents: updated}}
end
def handle_info({:inet_reply, _, _}, state), do: {:noreply, state}
@spec system_metrics(String.t() | nil) :: fun()
defp system_metrics(url)
defp system_metrics(nil), do: fn _, _, _ -> :ok end
defp system_metrics(url) do
{:ok, socket, header} = Metrics.open(url)
fqdn =
:net_adm.localhost()
|> :net_adm.dns_hostname()
|> elem(1)
|> to_string()
|> String.trim()
|> String.downcase()
tags =
[
"host:#{fqdn}",
System.get_env("STATSD_TAGS")
]
|> Enum.reject(&is_nil/1)
|> Enum.join(",")
static = "kvasir.agent_server.disks:"
prefix = IO.iodata_to_binary([header, static])
midfix = "|g|##{tags},"
fn %{agent: agent, id: id, partition: partition}, path, used ->
add =
[
"disk:#{path}",
"agent:#{String.downcase(inspect(agent))}",
"topic:#{id}",
unless partition == "*" do
m = partition |> String.split(" ") |> List.last() |> String.trim("\"")
"partition:#{m}"
end
]
|> Enum.reject(&is_nil/1)
|> Enum.join(",")
Port.command(socket, [prefix, to_string(used), midfix, add])
end
end
end