Packages

appsignal

1.6.6
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
appsignal lib appsignal plug.ex
Raw

lib/appsignal/plug.ex

if Appsignal.plug?() do
defmodule Appsignal.Plug do
@moduledoc """
Plug handler for Phoenix requests
"""
alias Appsignal.Config
defmacro __using__(_) do
quote do
@transaction Application.get_env(
:appsignal,
:appsignal_transaction,
Appsignal.Transaction
)
def call(conn, opts) do
transaction =
@transaction.generate_id()
|> @transaction.start(:http_request)
|> Appsignal.Plug.try_set_action(conn)
conn = Plug.Conn.put_private(conn, :appsignal_transaction, transaction)
try do
super(conn, opts)
catch
kind, reason -> Appsignal.Plug.handle_error(conn, kind, reason)
else
conn -> Appsignal.Plug.finish_with_conn(transaction, conn)
end
end
end
end
@transaction Application.get_env(
:appsignal,
:appsignal_transaction,
Appsignal.Transaction
)
def handle_error(_conn, :error, %Plug.Conn.WrapperError{} = wrapper) do
%{conn: conn, kind: kind, reason: reason, stack: stack} = wrapper
handle_error(conn, kind, wrapper, reason, stack)
end
def handle_error(conn, kind, reason) do
handle_error(conn, kind, reason, reason, System.stacktrace())
end
def handle_error(
%Plug.Conn{private: %{appsignal_transaction: transaction}} = conn,
kind,
reason,
wrapped_reason,
stack
) do
exception = Exception.normalize(kind, wrapped_reason, stack)
case Appsignal.Plug.extract_error_metadata(exception) do
{reason, message} ->
transaction
|> @transaction.set_error(reason, message, stack)
|> finish_with_conn(conn)
nil ->
:ok
end
:erlang.raise(kind, reason, stack)
end
def handle_error(_conn, kind, reason, _wrapped_reason, stack) do
:erlang.raise(kind, reason, stack)
end
def finish_with_conn(transaction, conn) do
if @transaction.finish(transaction) == :sample do
@transaction.set_request_metadata(transaction, conn)
end
:ok = @transaction.complete(transaction)
conn
end
def try_set_action(transaction, conn) do
case Appsignal.Plug.extract_action(conn) do
nil -> transaction
action -> @transaction.set_action(transaction, action)
end
end
@doc """
Returns a tuple with the exception's reason and message unless the error has
a status code under 500.
"""
def extract_error_metadata(%{plug_status: status}) when status < 500 do
nil
end
def extract_error_metadata(%Plug.Conn.WrapperError{reason: reason = %{}}) do
Appsignal.ErrorHandler.extract_reason_and_message(reason, "HTTP request error")
end
def extract_error_metadata(reason) do
Appsignal.ErrorHandler.extract_reason_and_message(reason, "HTTP request error")
end
@doc false
def extract_error_metadata(reason, conn, stack) do
IO.warn(
"Appsignal.Plug.extract_error_metadata/3 is deprecated. Use Appsignal.Plug.extract_error_metadata/1 instead."
)
{reason, message} = extract_error_metadata(reason)
{reason, message, stack, conn}
end
def extract_action(%Plug.Conn{
private: %{phoenix_action: action, phoenix_controller: controller}
}) do
merge_action_and_controller(action, controller)
end
def extract_action(%Plug.Conn{private: %{phoenix_endpoint: _}}), do: nil
def extract_action(%Plug.Conn{method: _method, request_path: _path}) do
"unknown"
end
def extract_sample_data(
%Plug.Conn{
params: params,
host: host,
method: method,
request_path: request_path,
port: port
} = conn
) do
%{
"params" => Appsignal.Utils.MapFilter.filter_values(
params,
Appsignal.Utils.MapFilter.get_filter_parameters()
),
"environment" =>
%{
"host" => host,
"method" => method,
"request_path" => request_path,
"port" => port,
"request_uri" => url(conn)
}
|> Map.merge(extract_request_headers(conn))
}
end
def extract_request_headers(%Plug.Conn{req_headers: req_headers}) do
for {key, value} <- req_headers,
key in (Config.request_headers()) do
{"req_headers.#{key}", value}
end
|> Enum.into(%{})
end
def extract_meta_data(%Plug.Conn{method: method, request_path: path} = conn) do
request_id =
conn
|> Plug.Conn.get_resp_header("x-request-id")
|> List.first()
%{
"method" => method,
"path" => path,
"request_id" => request_id
}
end
defp merge_action_and_controller(action, controller) when is_atom(controller) do
merge_action_and_controller(
action,
controller |> Atom.to_string() |> String.trim_leading("Elixir.")
)
end
defp merge_action_and_controller(action, controller) do
"#{controller}##{action}"
end
defp url(%Plug.Conn{scheme: scheme, host: host, port: port, request_path: request_path}) do
"#{scheme}://#{host}:#{port}#{request_path}"
end
end
end