Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Logger middleware to configured at runtime #409

Merged
merged 1 commit into from
Aug 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 34 additions & 13 deletions lib/tesla/middleware/logger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ defmodule Tesla.Middleware.Logger do
## Options
- `:log_level` - custom function for calculating log level (see below)
- `:filter_headers` - sanitizes sensitive headers before logging in debug mode (see below)
- `:debug` - show detailed request/response logging

## Custom log format

Expand Down Expand Up @@ -106,6 +107,23 @@ defmodule Tesla.Middleware.Logger do
# config/dev.local.exs
config :tesla, Tesla.Middleware.Logger, debug: false
```

This config will be fetched at compile-time.

In order to be able to set `:debug` at runtime we can
pass it as a option to the middleware at runtime.

```elixir
def client do
middleware = [
# ...
{Tesla.Middleware.Logger, debug: false}
]

Tesla.client(middleware)
end
```

### Filter headers

To sanitize sensitive headers such as `authorization` in
Expand Down Expand Up @@ -133,20 +151,23 @@ defmodule Tesla.Middleware.Logger do
@impl Tesla.Middleware
def call(env, next, opts) do
{time, response} = :timer.tc(Tesla, :run, [env, next])
level = log_level(response, opts)

config = Keyword.merge(@config, opts)

level = log_level(response, config)
Logger.log(level, fn -> Formatter.format(env, response, time, @format) end)

if Keyword.get(@config, :debug, true) do
Logger.debug(fn -> debug(env, response, opts) end)
if Keyword.get(config, :debug, true) do
Logger.debug(fn -> debug(env, response, config) end)
end

response
end

defp log_level({:error, _}, _), do: :error

defp log_level({:ok, env}, opts) do
case Keyword.get(opts, :log_level) do
defp log_level({:ok, env}, config) do
case Keyword.get(config, :log_level) do
nil ->
default_log_level(env)

Expand Down Expand Up @@ -175,28 +196,28 @@ defmodule Tesla.Middleware.Logger do
@debug_no_body "(no body)"
@debug_stream "[Elixir.Stream]"

defp debug(request, {:ok, response}, opts) do
defp debug(request, {:ok, response}, config) do
[
"\n>>> REQUEST >>>\n",
debug_query(request.query),
?\n,
debug_headers(request.headers, opts),
debug_headers(request.headers, config),
?\n,
debug_body(request.body),
?\n,
"\n<<< RESPONSE <<<\n",
debug_headers(response.headers, opts),
debug_headers(response.headers, config),
?\n,
debug_body(response.body)
]
end

defp debug(request, {:error, error}, opts) do
defp debug(request, {:error, error}, config) do
[
"\n>>> REQUEST >>>\n",
debug_query(request.query),
?\n,
debug_headers(request.headers, opts),
debug_headers(request.headers, config),
?\n,
debug_body(request.body),
?\n,
Expand All @@ -213,10 +234,10 @@ defmodule Tesla.Middleware.Logger do
|> Enum.map(fn {k, v} -> ["Query: ", to_string(k), ": ", to_string(v), ?\n] end)
end

defp debug_headers([], _opts), do: @debug_no_headers
defp debug_headers([], _config), do: @debug_no_headers

defp debug_headers(headers, opts) do
filtered = Keyword.get(opts, :filter_headers, [])
defp debug_headers(headers, config) do
filtered = Keyword.get(config, :filter_headers, [])

Enum.map(headers, fn {k, v} ->
v = if k in filtered, do: "[FILTERED]", else: v
Expand Down
10 changes: 10 additions & 0 deletions test/tesla/middleware/logger_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ defmodule Tesla.Middleware.LoggerTest do
assert log =~ "/ok -> 200"
assert log =~ "Stream"
end

test "config at runtime" do
client =
Tesla.client([{Tesla.Middleware.Logger, debug: false}], fn env ->
{:ok, %{env | body: "response"}}
end)

log = capture_log(fn -> Tesla.get(client, "/ok", query: %{"test" => "true"}) end)
refute log =~ "Query: test: true"
end
end

describe "Debug mode with custom structs" do
Expand Down