Packages

A plug to enable hackney_trace

Current section

Files

Jump to
plug_hackney_trace lib plug_hackney_trace.ex
Raw

lib/plug_hackney_trace.ex

defmodule PlugHackneyTrace do
@moduledoc """
A plug to enable `hackney_trace` in [hackney](https://github.com/benoitc/hackney).
To use it, just plug it into the desired module.
```
plug PlugHackneyTrace, trace: :min
```
In a Phoenix powered project, you can plug it into a specific action.
```
plug PlugHackneyTrace when action in [:show]
```
## Logging
You can log the output of `hackney_trace` or handle it by a custom function. If you
pass an `atom` for `log` option, this module will log the contents with `Logger` module.
```
plug PlugHackneyTrace, log: :info
```
Or you can specify the custom function for handle the output of `hackney_trace`.
```
plug PlugHackneyTrace, log: fn contents -> ... end
```
## Options
* `:log` - The log level for `Logger` or a function which handles
contents of traces. Default is `:info`.
* `:trace` - The trace level for `hackney_trace`. Default is `:max`.
"""
import PlugHackneyTrace.Helpers
require Logger
@behaviour Plug
def init(opts), do: opts
def call(conn, opts) do
log = Keyword.get(opts, :log, :info)
trace_level = Keyword.get(opts, :trace, :max)
with {:ok, path} <- generate_temporary_filepath(),
:ok <- :hackney_trace.enable(trace_level, to_charlist(path)) do
Plug.Conn.register_before_send(conn, fn conn ->
:hackney_trace.disable()
with {:ok, content} <- File.read(path) do
handle_trace_content(content, log)
else
{:error, posix_code} ->
Logger.warn("Couldn't read traced contents from the file at #{path}: #{posix_code}")
end
with {:error, posix_code} <- File.rm(path) do
Logger.warn(
"Couldn't remove a temporary file for hackney_trace at #{path}: #{posix_code}"
)
end
conn
end)
else
error ->
Logger.warn("Couldn't enable hackney_trace: #{transform_error(error)}")
conn
end
end
## Private
@spec handle_trace_content(binary, atom | (binary -> any)) :: any
defp handle_trace_content(contents, log_level) when is_atom(log_level) do
Logger.bare_log(log_level, contents)
end
defp handle_trace_content(contents, handler) when is_function(handler) do
handler.(contents)
end
@spec transform_error(term) :: String.t()
defp transform_error({:error, reason}), do: inspect(reason)
defp transform_error(error), do: inspect(error)
end