farmbot_os/farmbot_core/lib/farmbot_core/log_storage/logger.ex

142 lines
4.1 KiB
Elixir

defmodule FarmbotCore.Logger do
@moduledoc """
Log messages to Farmot endpoints.
"""
alias FarmbotCore.{Log, Logger.Repo}
import Ecto.Query
@log_types [:info, :debug, :busy, :warn, :success, :error, :fun, :assertion]
@doc "Send a debug message to log endpoints"
defmacro debug(verbosity, message, meta \\ []) do
quote bind_quoted: [verbosity: verbosity, message: message, meta: meta] do
FarmbotCore.Logger.dispatch_log(__ENV__, :debug, verbosity, message, meta)
end
end
@doc "Send an info message to log endpoints"
defmacro info(verbosity, message, meta \\ []) do
quote bind_quoted: [verbosity: verbosity, message: message, meta: meta] do
FarmbotCore.Logger.dispatch_log(__ENV__, :info, verbosity, message, meta)
end
end
@doc "Send an busy message to log endpoints"
defmacro busy(verbosity, message, meta \\ []) do
quote bind_quoted: [verbosity: verbosity, message: message, meta: meta] do
FarmbotCore.Logger.dispatch_log(__ENV__, :busy, verbosity, message, meta)
end
end
@doc "Send an success message to log endpoints"
defmacro success(verbosity, message, meta \\ []) do
quote bind_quoted: [verbosity: verbosity, message: message, meta: meta] do
FarmbotCore.Logger.dispatch_log(__ENV__, :success, verbosity, message, meta)
end
end
@doc "Send an warn message to log endpoints"
defmacro warn(verbosity, message, meta \\ []) do
quote bind_quoted: [verbosity: verbosity, message: message, meta: meta] do
FarmbotCore.Logger.dispatch_log(__ENV__, :warn, verbosity, message, meta)
end
end
@doc "Send an error message to log endpoints"
defmacro error(verbosity, message, meta \\ []) do
quote bind_quoted: [verbosity: verbosity, message: message, meta: meta] do
FarmbotCore.Logger.dispatch_log(__ENV__, :error, verbosity, message, meta)
end
end
@doc false
defmacro fun(verbosity, message, meta \\ []) do
quote bind_quoted: [verbosity: verbosity, message: message, meta: meta] do
FarmbotCore.Logger.dispatch_log(__ENV__, :fun, verbosity, message, meta)
end
end
def insert_log!(params) do
changeset = Log.changeset(%Log{}, params)
try do
hash = Ecto.Changeset.get_field(changeset, :hash)
case Repo.get_by(Log, hash: hash) do
nil ->
Repo.insert!(changeset)
old ->
params =
params
|> Map.put(:inserted_at, DateTime.utc_now())
|> Map.put(:duplicates, old.duplicates + 1)
old
|> Log.changeset(params)
|> Repo.update!()
end
catch
kind, err ->
IO.warn("Error inserting log: #{kind} #{inspect(err)}", __STACKTRACE__)
Ecto.Changeset.apply_changes(changeset)
end
end
@doc "Gets a log by it's id, deletes it."
def handle_log(id) do
case Repo.get(FarmbotCore.Log, id) do
%Log{} = log -> Repo.delete!(log)
nil -> nil
end
end
@doc "Gets all available logs and deletes them."
def handle_all_logs do
Repo.all(from(l in FarmbotCore.Log, order_by: l.inserted_at))
|> Enum.map(&Repo.delete!/1)
end
@doc false
def dispatch_log(%Macro.Env{} = env, level, verbosity, message, meta)
when level in @log_types and
is_number(verbosity) and
is_binary(message) and
is_list(meta) do
fun =
case env.function do
{fun, ar} -> "#{fun}/#{ar}"
nil -> "no_function"
end
%{
level: level,
verbosity: verbosity,
message: message,
meta: Map.new(meta),
function: fun,
file: env.file,
line: env.line,
module: env.module
}
|> dispatch_log()
end
@doc false
def dispatch_log(params) do
log = insert_log!(params)
FarmbotCore.LogExecutor.execute(log)
end
@doc "Helper function for deciding if a message should be logged or not."
def should_log?(module, verbosity)
def should_log?(nil, verbosity) when verbosity <= 3, do: true
def should_log?(nil, _), do: false
def should_log?(module, verbosity) when verbosity <= 3 do
List.first(Module.split(module)) =~ "Farmbot"
end
def should_log?(_, _), do: false
end