Current section

Files

Jump to
disco_log lib disco_log.ex
Raw

lib/disco_log.ex

defmodule DiscoLog do
@moduledoc """
Send messages to Discord
All functions in this module accept optional `context` and `config` parameters.
* `context` is the last opportunity to assign some metadata that will be
attached to the message or occurrence. Occurrences will additionally be tagged
if context key names match existing channel tags.
* `config` is important if you're running [advanced configuration](advanced-configuration.md)
"""
alias DiscoLog.Error
alias DiscoLog.Config
alias DiscoLog.Context
alias DiscoLog.Storage
alias DiscoLog.Discord.API
alias DiscoLog.Discord.Prepare
@doc """
Report catched error to occurrences channel
This function reports an error directly to the occurrences channel, bypassing logging.
Example:
try do
raise "Unexpected!"
catch
kind, reason -> DiscoLog.report(kind, reason, __STACKTRACE__)
end
"""
@spec report(Exception.kind(), any(), Exception.stacktrace(), Context.t(), Config.t() | nil) ::
API.response()
def report(kind, reason, stacktrace, context \\ %{}, config \\ nil) do
config = maybe_read_config(config)
context = Map.merge(DiscoLog.Context.get(), context)
error = Error.new(kind, reason, stacktrace) |> Error.enrich(config)
log_occurrence(error, context, config)
end
@doc false
def log_occurrence(error, context, config) do
config.supervisor_name
|> Storage.get_thread_id(error.fingerprint)
|> case do
nil ->
available_tags = Storage.get_tags(config.supervisor_name) || %{}
applied_tags =
context
|> Map.keys()
|> Enum.map(&to_string/1)
|> Enum.filter(&(&1 in Map.keys(available_tags)))
|> Enum.map(&Map.fetch!(available_tags, &1))
message =
Prepare.prepare_occurrence(error, context, applied_tags)
with {:ok, %{status: 201, body: %{"id" => thread_id}}} = response <-
API.post_thread(config.discord_client, config.occurrences_channel_id, message) do
Storage.add_thread_id(config.supervisor_name, error.fingerprint, thread_id)
response
end
thread_id ->
message = Prepare.prepare_occurrence_message(error, context)
API.post_message(config.discord_client, thread_id, message)
end
end
@doc """
Sends text message to the channel configured as `info_channel_id`
"""
@spec log_info(String.t(), Context.t(), Config.t() | nil) :: API.response()
def log_info(message, context \\ %{}, config \\ nil) do
config = maybe_read_config(config)
message = Prepare.prepare_message(message, context)
API.post_message(config.discord_client, config.info_channel_id, message)
end
@doc """
Sends text message to the channel configures as `error_channel_id`
"""
@spec log_error(String.t(), Context.t(), Config.t() | nil) :: API.response()
def log_error(message, context \\ %{}, config \\ nil) do
config = maybe_read_config(config)
message = Prepare.prepare_message(message, context)
API.post_message(config.discord_client, config.error_channel_id, message)
end
defp maybe_read_config(nil), do: DiscoLog.Config.read!()
defp maybe_read_config(config), do: config
end