Using Rollbax in Plug-based applications
Plug provides the Plug.ErrorHandler
plug which plays very well with Rollbax. As you can see in the documentation for Plug.ErrorHandler
, this plug can be used to “catch” exceptions that happen inside a given plug and act on them. This can be used to report all exceptions happening in that plug to Rollbar. For example:
defmodule MyApp.Router do
use Plug.Router # or `use MyApp.Web, :router` for Phoenix apps
use Plug.ErrorHandler
defp handle_errors(conn, %{kind: kind, reason: reason, stack: stacktrace}) do
Rollbax.report(kind, reason, stacktrace)
end
end
Rollbax also supports attaching metadata to a reported exception as well as overriding Rollbar data for a reported exception. Both these can be used to have more detailed reports. For example, in the code snippet above, we could report the request parameters as metadata to be attached to the exception:
defp handle_errors(conn, %{kind: kind, reason: reason, stack: stacktrace}) do
Rollbax.report(kind, reason, stacktrace, %{method: conn.method})
end
Since Rollbar supports the concept of “request” and “server” in the Item POST API, a lot of data that Rollbar will be able to understand can be attached to a reported exceptions. These data is not referred as “custom data” but rather as occurrence data. To add data about the host, the request, and more that Rollbax understands pass them as the occurrence_data
argument. For example:
defp handle_errors(conn, %{kind: kind, reason: reason, stack: stacktrace}) do
conn =
conn
|> Plug.Conn.fetch_cookies()
|> Plug.Conn.fetch_query_params()
params =
case conn.params do
%Plug.Conn.Unfetched{aspect: :params} -> "unfetched"
other -> other
end
occurrence_data = %{
"request" => %{
"cookies" => conn.req_cookies,
"url" => "#{conn.scheme}://#{conn.host}:#{conn.port}#{conn.request_path}",
"user_ip" => List.to_string(:inet.ntoa(conn.remote_ip)),
"headers" => Enum.into(conn.req_headers, %{}),
"method" => conn.method,
"params" => params,
},
"server" => %{
"pid" => System.get_env("MY_SERVER_PID"),
"host" => "#{System.get_env("MY_HOSTNAME")}:#{System.get_env("MY_PORT")}",
"root" => System.get_env("MY_APPLICATION_PATH"),
},
}
Rollbax.report(kind, reason, stacktrace, _custom_data = %{}, occurrence_data)
end
Check the documentation for the Rollbar API for all the supported values that can form a “request”.
Sensitive data
In the examples above, all parameters are fetched from the connection and forwarded to Rollbar (in the "params"
key); this means that any sensitive data such as passwords or authentication keys will be sent to Rollbar as well. A good idea may be to scrub any sensitive data out of the parameters before reporting errors to Rollbar. For example:
defp handle_errors(conn, error) do
conn =
conn
|> Plug.Conn.fetch_cookies()
|> Plug.Conn.fetch_query_params()
params =
for {key, _value} = tuple <- conn.params, into: %{} do
if key in ["password", "password_confirmation"] do
{key, "[FILTERED]"}
else
tuple
end
end
# Same as the examples above
end