Created
July 14, 2021 07:02
-
-
Save tlvenn/5c239e7df76c0d266509ba18ef1785f0 to your computer and use it in GitHub Desktop.
LoggerJSON Formatters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Web.LoggerPlugFormatter do | |
@moduledoc """ | |
Formats connection into Logger metadata: | |
* `connection.type` - type of connection (Sent or Chunked); | |
* `connection.method` - HTTP request method; | |
* `connection.request_path` - HTTP request path; | |
* `connection.request_id` - value of `X-Request-ID` response header (see `Plug.RequestId`); | |
* `connection.status` - HTTP status code sent to a client; | |
* `connection.params` - HTTP filtered params; | |
* `client.user_agent` - value of `User-Agent` header; | |
* `client.ip' - value of `X-Forwarded-For` header if present, otherwise - remote IP of a connected client; | |
* `client.api_version' - version of API that was requested by a client; | |
* `node.hostname` - system hostname; | |
* `node.pid` - Erlang VM process identifier; | |
* `phoenix.controller` - Phoenix controller that processed the request; | |
* `phoenix.action` - Phoenix action that processed the request; | |
* `latency_μs` - time in microseconds taken to process the request. | |
""" | |
import Jason.Helpers, only: [json_map: 1] | |
@doc false | |
def build_metadata(conn, latency, client_version_header) do | |
# credo:disable-for-next-line | |
latency_μs = System.convert_time_unit(latency, :native, :microsecond) | |
user_agent = LoggerJSON.Plug.get_header(conn, "user-agent") | |
ip = remote_ip(conn) | |
api_version = LoggerJSON.Plug.get_header(conn, client_version_header) | |
{hostname, vm_pid} = node_metadata() | |
phoenix_metadata(conn) ++ | |
[ | |
connection: | |
json_map( | |
type: connection_type(conn), | |
method: conn.method, | |
request_path: conn.request_path, | |
status: conn.status, | |
params: fetch_params(conn.params) | |
), | |
client: | |
json_map( | |
user_agent: user_agent, | |
ip: ip, | |
api_version: api_version | |
), | |
node: json_map(hostname: to_string(hostname), vm_pid: vm_pid), | |
latency_μs: latency_μs | |
] | |
end | |
defp connection_type(%{state: :set_chunked}), do: "chunked" | |
defp connection_type(_), do: "sent" | |
defp remote_ip(conn) do | |
LoggerJSON.Plug.get_header(conn, "x-forwarded-for") || | |
to_string(:inet_parse.ntoa(conn.remote_ip)) | |
end | |
defp phoenix_metadata(%{private: %{phoenix_controller: controller, phoenix_action: action}}) do | |
[phoenix: %{controller: controller, action: action}] | |
end | |
defp phoenix_metadata(_conn) do | |
[] | |
end | |
defp node_metadata do | |
{:ok, hostname} = :inet.gethostname() | |
vm_pid = | |
case Integer.parse(System.get_pid()) do | |
{pid, _units} -> pid | |
_ -> nil | |
end | |
{hostname, vm_pid} | |
end | |
defp fetch_params(%Plug.Conn.Unfetched{aspect: :params}), do: %{} | |
defp fetch_params(params), do: discard_values(params, ["password"]) | |
# https://github.com/phoenixframework/phoenix/blob/v1.4.16/lib/phoenix/logger.ex#L73-L91 | |
defp discard_values(%{__struct__: mod} = struct, _params) when is_atom(mod) do | |
struct | |
end | |
defp discard_values(%{} = map, params) do | |
Enum.into(map, %{}, fn {k, v} -> | |
if is_binary(k) and String.contains?(k, params) do | |
{k, "[FILTERED]"} | |
else | |
{k, discard_values(v, params)} | |
end | |
end) | |
end | |
defp discard_values([_ | _] = list, params) do | |
Enum.map(list, &discard_values(&1, params)) | |
end | |
defp discard_values(other, _params), do: other | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment