farmbot_os/farmbot_ext/lib/amqp/log_transport.ex

86 lines
2.6 KiB
Elixir

defmodule Farmbot.AMQP.LogTransport do
use GenServer
use AMQP
require Farmbot.Logger
import Farmbot.Config, only: [update_config_value: 4]
@exchange "amq.topic"
defstruct [:conn, :chan, :bot, :state_cache]
alias __MODULE__, as: State
@doc false
def start_link(args) do
GenServer.start_link(__MODULE__, args, [name: __MODULE__])
end
def init([conn, jwt]) do
Process.flag(:sensitive, true)
Farmbot.Registry.subscribe()
{:ok, chan} = AMQP.Channel.open(conn)
:ok = Basic.qos(chan, [global: true])
state = struct(State, [conn: conn, chan: chan, bot: jwt.bot])
for l <- Farmbot.Logger.handle_all_logs() do
do_handle_log(l, state)
end
{:ok, state}
end
def terminate(reason, state) do
ok_reasons = [:normal, :shutdown, :token_refresh]
update_config_value(:bool, "settings", "ignore_fbos_config", false)
if reason not in ok_reasons do
Farmbot.Logger.error 1, "Logger amqp client Died: #{inspect reason}"
update_config_value(:bool, "settings", "log_amqp_connected", true)
end
# If a channel was still open, close it.
if state.chan, do: AMQP.Channel.close(state.chan)
end
def handle_info({Farmbot.Registry, {Farmbot.Logger, {:log_ready, id}}}, state) do
if log = Farmbot.Logger.handle_log(id) do
do_handle_log(log, state)
end
{:noreply, state}
end
def handle_info({Farmbot.Registry, {Farmbot.BotState, bot_state}}, state) do
{:noreply, %{state | state_cache: bot_state}}
end
def handle_info({Farmbot.Registry, _}, state) do
{:noreply, state}
end
defp do_handle_log(log, state) do
if Farmbot.Logger.should_log?(log.module, log.verbosity) do
fb = %{position: %{x: -1, y: -1, z: -1}}
location_data = Map.get(state.state_cache || %{}, :location_data, fb)
log_without_pos = %{
type: log.level,
x: nil, y: nil, z: nil,
verbosity: log.verbosity,
major_version: log.version.major,
minor_version: log.version.minor,
patch_version: log.version.patch,
created_at: DateTime.from_naive!(log.inserted_at, "Etc/UTC") |> DateTime.to_unix(),
channels: log.meta[:channels] || [],
message: log.message
}
log = add_position_to_log(log_without_pos, location_data)
push_bot_log(state.chan, state.bot, log)
end
end
defp push_bot_log(chan, bot, log) do
json = Farmbot.JSON.encode!(log)
:ok = AMQP.Basic.publish chan, @exchange, "bot.#{bot}.logs", json
end
defp add_position_to_log(%{} = log, %{position: %{} = pos}) do
Map.merge(log, pos)
end
end