Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F114314
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/tesla/middleware/logger.ex b/lib/tesla/middleware/logger.ex
index b579e46..c7e0c50 100644
--- a/lib/tesla/middleware/logger.ex
+++ b/lib/tesla/middleware/logger.ex
@@ -1,190 +1,188 @@
defmodule Tesla.Middleware.Logger do
@behaviour Tesla.Middleware
@moduledoc """
Log requests as single line.
Logs request method, url, response status and time taken in milliseconds.
### Example usage
```
defmodule MyClient do
use Tesla
plug Tesla.Middleware.Logger
end
```
### Logger output
```
2017-09-30 13:39:06.663 [info] GET http://example.com -> 200 (736.988 ms)
```
See `Tesla.Middleware.DebugLogger` to log request/response body
"""
require Logger
def call(env, next, _opts) do
- {time, env} = :timer.tc(Tesla, :run, [env, next])
- _ = log(env, time)
- env
- rescue
- ex in Tesla.Error ->
- stacktrace = System.stacktrace()
- _ = log(env, ex)
- reraise ex, stacktrace
+ {time, result} = :timer.tc(Tesla, :run, [env, next])
+ _ = log(env, result, time)
+ result
end
- defp log(env, %Tesla.Error{message: message}) do
- Logger.error("#{normalize_method(env)} #{env.url} -> #{message}")
+ defp log(env, {:error, reason}, _time) do
+ Logger.error("#{normalize_method(env)} #{env.url} -> #{inspect reason}")
end
- defp log(env, time) do
+ defp log(_env, {:ok, env}, time) do
ms = :io_lib.format("~.3f", [time / 1000])
message = "#{normalize_method(env)} #{env.url} -> #{env.status} (#{ms} ms)"
cond do
env.status >= 400 -> Logger.error(message)
env.status >= 300 -> Logger.warn(message)
true -> Logger.info(message)
end
end
defp normalize_method(env) do
env.method |> to_string() |> String.upcase()
end
end
defmodule Tesla.Middleware.DebugLogger do
@behaviour Tesla.Middleware
@moduledoc """
Log full reqeust/response content
### Example usage
```
defmodule MyClient do
use Tesla
plug Tesla.Middleware.DebugLogger
end
```
### Logger output
```
2017-09-30 13:41:56.281 [debug] > POST https://httpbin.org/post
2017-09-30 13:41:56.281 [debug]
2017-09-30 13:41:56.281 [debug] > a=3
2017-09-30 13:41:56.432 [debug]
2017-09-30 13:41:56.432 [debug] < HTTP/1.1 200
2017-09-30 13:41:56.432 [debug] < access-control-allow-credentials: true
2017-09-30 13:41:56.432 [debug] < access-control-allow-origin: *
2017-09-30 13:41:56.432 [debug] < connection: keep-alive
2017-09-30 13:41:56.432 [debug] < content-length: 280
2017-09-30 13:41:56.432 [debug] < content-type: application/json
2017-09-30 13:41:56.432 [debug] < date: Sat, 30 Sep 2017 11:41:55 GMT
2017-09-30 13:41:56.432 [debug] < server: meinheld/0.6.1
2017-09-30 13:41:56.432 [debug] < via: 1.1 vegur
2017-09-30 13:41:56.432 [debug] < x-powered-by: Flask
2017-09-30 13:41:56.432 [debug] < x-processed-time: 0.0011260509491
2017-09-30 13:41:56.432 [debug]
2017-09-30 13:41:56.432 [debug] > {
"args": {},
"data": "a=3",
"files": {},
"form": {},
"headers": {
"Connection": "close",
"Content-Length": "3",
"Content-Type": "",
"Host": "httpbin.org"
},
"json": null,
"origin": "0.0.0.0",
"url": "https://httpbin.org/post"
}
```
"""
require Logger
def call(env, next, _opts) do
env
|> log_request
|> log_headers("> ")
|> log_params("> ")
|> log_body("> ")
|> Tesla.run(next)
- |> log_response
- |> log_headers("< ")
- |> log_body("< ")
- rescue
- ex in Tesla.Error ->
- stacktrace = System.stacktrace()
- _ = log_exception(ex, "< ")
- reraise ex, stacktrace
+ |> case do
+ {:ok, env} ->
+ env
+ |> log_response
+ |> log_headers("< ")
+ |> log_body("< ")
+ {:ok, env}
+ {:error, reason} ->
+ log_exception(reason, "< ")
+ {:error, reason}
+ end
end
defp log_request(env) do
_ = Logger.debug("> #{env.method |> to_string |> String.upcase()} #{env.url}")
env
end
defp log_response(env) do
_ = Logger.debug("")
_ = Logger.debug("< HTTP/1.1 #{env.status}")
env
end
defp log_headers(env, prefix) do
for {k, v} <- env.headers do
_ = Logger.debug("#{prefix}#{k}: #{v}")
end
env
end
defp log_params(env, prefix) do
for {k, v} <- env.query do
_ = Logger.debug("#{prefix} Query Param '#{k}': '#{v}'")
end
env
end
defp log_body(%Tesla.Env{} = env, _prefix) do
Map.update!(env, :body, &log_body(&1, "> "))
end
defp log_body(nil, _), do: nil
defp log_body([], _), do: nil
defp log_body(%Stream{} = stream, prefix), do: log_body_stream(stream, prefix)
defp log_body(stream, prefix) when is_function(stream), do: log_body_stream(stream, prefix)
defp log_body(%Tesla.Multipart{} = mp, prefix), do: log_multipart_body(mp, prefix)
defp log_body(data, prefix) when is_binary(data) or is_list(data) do
_ = Logger.debug("")
_ = Logger.debug(prefix <> to_string(data))
data
end
defp log_body_stream(stream, prefix) do
_ = Logger.debug("")
Stream.each(stream, fn line -> Logger.debug(prefix <> line) end)
end
defp log_multipart_body(%Tesla.Multipart{} = mp, prefix) do
_ = Logger.debug("")
_ = Logger.debug(prefix <> "boundary: " <> mp.boundary)
_ = Logger.debug(prefix <> "content_type_params: " <> inspect(mp.content_type_params))
Enum.each(mp.parts, &Logger.debug(prefix <> inspect(&1)))
mp
end
- defp log_exception(%Tesla.Error{message: message, reason: reason}, prefix) do
- _ = Logger.debug(prefix <> message <> " (#{inspect(reason)})")
+ defp log_exception(reason, prefix) do
+ _ = Logger.debug(prefix <> " (#{inspect(reason)})")
end
end
diff --git a/test/tesla/middleware/logger_test.exs b/test/tesla/middleware/logger_test.exs
index bee7362..a41e4f0 100644
--- a/test/tesla/middleware/logger_test.exs
+++ b/test/tesla/middleware/logger_test.exs
@@ -1,81 +1,80 @@
defmodule Tesla.Middleware.LoggerTest do
use ExUnit.Case, async: false
defmodule Client do
use Tesla
plug Tesla.Middleware.Logger
plug Tesla.Middleware.DebugLogger
adapter fn env ->
- {status, body} =
- case env.url do
- "/connection-error" ->
- raise %Tesla.Error{message: "adapter error: :econnrefused", reason: :econnrefused}
+ env = Tesla.put_header(env, "content-type", "text/plain")
- "/server-error" ->
- {500, "error"}
+ case env.url do
+ "/connection-error" ->
+ {:error, :econnrefused}
- "/client-error" ->
- {404, "error"}
+ "/server-error" ->
+ {:ok, %{env | status: 500, body: "error"}}
- "/redirect" ->
- {301, "moved"}
+ "/client-error" ->
+ {:ok, %{env | status: 404, body: "error"}}
- "/ok" ->
- {200, "ok"}
- end
+ "/redirect" ->
+ {:ok, %{env | status: 301, body: "moved"}}
- %{env | status: status, headers: [{"content-type", "text/plain"}], body: body}
+ "/ok" ->
+ {:ok, %{env | status: 200, body: "ok"}}
+ end
end
end
import ExUnit.CaptureLog
test "connection error" do
log =
capture_log(fn ->
- assert_raise Tesla.Error, fn -> Client.get("/connection-error") end
+ assert {:error, _} = Client.get("/connection-error")
end)
- assert log =~ "/connection-error -> adapter error: :econnrefused"
+ assert log =~ "/connection-error -> :econnrefused"
end
test "server error" do
log = capture_log(fn -> Client.get("/server-error") end)
assert log =~ "/server-error -> 500"
end
test "client error" do
log = capture_log(fn -> Client.get("/client-error") end)
assert log =~ "/client-error -> 404"
end
test "redirect" do
log = capture_log(fn -> Client.get("/redirect") end)
assert log =~ "/redirect -> 301"
end
test "ok" do
log = capture_log(fn -> Client.get("/ok") end)
assert log =~ "/ok -> 200"
end
test "ok with params" do
log = capture_log(fn -> Client.get("/ok", query: %{"test" => "true"}) end)
assert log =~ "Query Param 'test': 'true'"
end
test "multipart" do
mp = Tesla.Multipart.new() |> Tesla.Multipart.add_field("field1", "foo")
log = capture_log(fn -> Client.post("/ok", mp) end)
assert log =~ "boundary: #{mp.boundary}"
assert log =~ inspect(List.first(mp.parts))
end
test "stream" do
stream = Stream.map(1..10, fn i -> "chunk: #{i}" end)
log = capture_log(fn -> Client.post("/ok", stream) end)
assert log =~ "/ok -> 200"
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Nov 26, 2:41 AM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40182
Default Alt Text
(8 KB)
Attached To
Mode
R28 tesla
Attached
Detach File
Event Timeline
Log In to Comment