Packages
raxx
0.15.0
1.1.0
1.0.1
1.0.0
1.0.0-rc.3
1.0.0-rc.2
retired
1.0.0-rc.1
retired
1.0.0-rc.0
retired
0.18.1
0.18.0
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.1
0.16.0
retired
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.14
0.14.13
0.14.12
0.14.11
0.14.10
0.14.9
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.1
0.11.0
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
0.0.1
Interface for HTTP webservers, frameworks and clients.
Current section
Files
Jump to
Current section
Files
lib/raxx/logger.ex
defmodule Raxx.Logger do
@moduledoc """
Middleware for basic logging in the format:
GET /index.html
Sent 200 in 572ms
May be used in any `Raxx.Server` module.
use Raxx.Logger, level: :debug
## Options
- `:level` - The log level this middleware will use for request and response information.
Default is `:info`.
"""
require Logger
defmacro __using__(options) do
{options, []} = Module.eval_quoted(__CALLER__, options)
level = Keyword.get(options, :level, :info)
quote do
@raxx_logger_level unquote(level)
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(_env) do
quote do
defoverridable Raxx.Server
@impl Raxx.Server
def handle_head(head, config) do
# NOTE Raxx servers can be nested, app metadata should not be overwritten.
if !Keyword.has_key?(Logger.metadata(), :"raxx.app") do
Logger.metadata("raxx.app": __MODULE__)
end
Logger.metadata("raxx.scheme": head.scheme)
Logger.metadata("raxx.authority": head.authority)
Logger.metadata("raxx.method": head.method)
# NOTE path segments are preserved as a list because formatting as url would assume canonical url
Logger.metadata("raxx.path": inspect(head.path))
Logger.metadata("raxx.query": inspect(head.query))
unquote(__MODULE__).process_head(head, @raxx_logger_level)
super(head, config)
|> unquote(__MODULE__).process_response(@raxx_logger_level)
end
@impl Raxx.Server
def handle_data(data, config) do
super(data, config)
|> unquote(__MODULE__).process_response(@raxx_logger_level)
end
@impl Raxx.Server
def handle_tail(tail, config) do
super(tail, config)
|> unquote(__MODULE__).process_response(@raxx_logger_level)
end
@impl Raxx.Server
def handle_info(message, config) do
super(message, config)
|> unquote(__MODULE__).process_response(@raxx_logger_level)
end
end
end
@doc false
def process_head(head, level) do
Logger.log(level, fn ->
Process.put(unquote(__MODULE__), %{start: System.monotonic_time()})
[Atom.to_string(head.method), ?\s, Raxx.normalized_path(head)]
end)
end
@doc false
def process_response(response = %Raxx.Response{}, level) do
log_response(response, level)
response
end
def process_response(reaction = {[response = %Raxx.Response{} | _parts], _state}, level) do
log_response(response, level)
reaction
end
def process_response(reaction, _level) do
reaction
end
defp log_response(response, level) do
Logger.log(level, fn ->
%{start: start} = Process.get(__MODULE__)
stop = System.monotonic_time()
diff = System.convert_time_unit(stop - start, :native, :microsecond)
[
response_type(response),
?\s,
Integer.to_string(response.status),
" in ",
formatted_diff(diff)
]
end)
end
defp formatted_diff(diff) when diff > 1000, do: [diff |> div(1000) |> Integer.to_string(), "ms"]
defp formatted_diff(diff), do: [Integer.to_string(diff), "µs"]
defp response_type(%{body: true}), do: "Chunked"
defp response_type(_), do: "Sent"
end