Elixir / Phoenix:如何自定义 HTTP 请求日志格式?
Elixir / Phoenix: How to customize HTTP request log format?
默认情况下,我的 Phoenix 应用程序会在大约 5 行日志输出中记录有关每个 HTTP 请求的基本信息。只要我将日志级别设置为 :debug
,我就可以看到每个请求的方法、路径、控制器和操作、参数、响应代码和持续时间:
2019-06-14 16:05:35.099 [info] GET /manage/projects/7qDjSk
2019-06-14 16:05:35.103 [debug] Processing with RTLWeb.Manage.ProjectController.show/2
Parameters: %{"project_uuid" => "7qDjSk"}
Pipelines: [:browser, :require_login]
2019-06-14 16:05:35.116 [info] Sent 200 in 17ms
这是一个很好的起点。但我想自定义应用程序以在一行中记录所有这些信息,这很有帮助,例如。在 Papertrail 这样的工具中筛选大量日志输出时。特别是我希望每个请求都以如下格式显示:
[PUT /manage/projects/74/prompts/290] params=%{"project_uuid" => "74", "prompt" => %{"html" => "<div>Test question 3</div>"}, "prompt_uuid" => "290"} user=38 (Topher Hunt) status=302 redirected_to=/manage/projects/74 duration=423ms
在 the Phoenix.Controller docs 中,我看到我可以配置 Phoenix 控制器日志记录的日志级别,或者完全禁用它,但我没有看到自定义格式的方法。我该怎么做?
这不是自定义输出的问题,而是 1) 禁用默认的 request-related 日志语句(通过分离相关的 :telemetry
处理程序)然后 2) 添加新的插件记录我想要的格式。
我是这样做的:
在application.ex
中,在start/2
函数中,分离Phoenix默认为您附加的遥测处理程序。 (调用 :telemetry.list_handlers([])
查看所有附加的侦听器。)
def start(_type, _args) do
# ...
# vvv ADD THESE vvv
:ok = :telemetry.detach({Phoenix.Logger, [:phoenix, :socket_connected]})
:ok = :telemetry.detach({Phoenix.Logger, [:phoenix, :channel_joined]})
:ok = :telemetry.detach({Phoenix.Logger, [:phoenix, :router_dispatch, :start]})
# ...
Supervisor.start_link(children, opts)
在lib/my_app_web/endpoint.ex
中,注释掉Plug.Telemetry
插件。
在 lib/my_app_web/endpoint.ex
中,在 Plug.Session 之前添加此自定义插件:
# One-line request logging. Must come before the session & router plugs.
plug MyAppWeb.RequestLogger
最后加上lib/my_app_web/plugs/request_logger.ex
。 (相应地调整细节;此实现假定 logged-in 用户结构存储在 conn.assigns.current_user
中):
# One-line full request logging inspired by Plug.Logger.
# See https://github.com/elixir-plug/plug/blob/v1.8.0/lib/plug/logger.ex
# Need to restart the server after updating this file.
defmodule MyAppWeb.RequestLogger do
require Logger
@behaviour Plug
def init(opts), do: opts
def call(conn, _opts) do
start_time = System.monotonic_time()
Plug.Conn.register_before_send(conn, fn(conn) ->
# We don't want passwords etc. being logged
params = inspect(Phoenix.Logger.filter_values(conn.params))
# Log any important session data eg. logged-in user
user = conn.assigns[:current_user]
user_string = if user, do: "#{user.id} (#{user.name})", else: "(none)"
# Note redirect, if any
redirect = Plug.Conn.get_resp_header(conn, "location")
redirect_string = if redirect != [], do: " redirected_to=#{redirect}", else: ""
# Calculate time taken (in ms for consistency)
stop_time = System.monotonic_time()
time_us = System.convert_time_unit(stop_time - start_time, :native, :microsecond)
time_ms = div(time_us, 100) / 10
Logger.log(:info,
"■ method=#{conn.method} path=#{conn.request_path} params=#{params} "<>
"user=#{user_string} status=#{conn.status}#{redirect_string} duration=#{time_ms}ms"
)
conn
end)
end
end
重新启动您的服务器,您现在应该只看到每个请求的一个日志行,格式如下:
2019-06-09 18:18:51.410 [info] ■ [PUT /manage/projects/7qDjSk/prompts/3tUrF9] params=%{"project_uuid" => "7qDjSk", "prompt" => %{"html" => "<div>Test question 3</div>"}, "prompt_uuid" => "3tUrF9"} user=1 (Topher Hunt) status=302 redirected_to=/manage/projects/7qDjSk duration=21ms
(注意:另一种更 best-practice 的方法是 :telemetry.attach
到 Phoenix 已经发出的 [:phoenix, :router_dispatch, :stop]
事件。这提供了我们需要的所有数据;见the Phoenix.Endpoint docs 了解更多详情。)
有用的参考资料:
还有这个,如果你想要JSON输出:https://github.com/Nebo15/logger_json/tree/master/lib/logger_json
默认情况下,我的 Phoenix 应用程序会在大约 5 行日志输出中记录有关每个 HTTP 请求的基本信息。只要我将日志级别设置为 :debug
,我就可以看到每个请求的方法、路径、控制器和操作、参数、响应代码和持续时间:
2019-06-14 16:05:35.099 [info] GET /manage/projects/7qDjSk
2019-06-14 16:05:35.103 [debug] Processing with RTLWeb.Manage.ProjectController.show/2
Parameters: %{"project_uuid" => "7qDjSk"}
Pipelines: [:browser, :require_login]
2019-06-14 16:05:35.116 [info] Sent 200 in 17ms
这是一个很好的起点。但我想自定义应用程序以在一行中记录所有这些信息,这很有帮助,例如。在 Papertrail 这样的工具中筛选大量日志输出时。特别是我希望每个请求都以如下格式显示:
[PUT /manage/projects/74/prompts/290] params=%{"project_uuid" => "74", "prompt" => %{"html" => "<div>Test question 3</div>"}, "prompt_uuid" => "290"} user=38 (Topher Hunt) status=302 redirected_to=/manage/projects/74 duration=423ms
在 the Phoenix.Controller docs 中,我看到我可以配置 Phoenix 控制器日志记录的日志级别,或者完全禁用它,但我没有看到自定义格式的方法。我该怎么做?
这不是自定义输出的问题,而是 1) 禁用默认的 request-related 日志语句(通过分离相关的 :telemetry
处理程序)然后 2) 添加新的插件记录我想要的格式。
我是这样做的:
在
application.ex
中,在start/2
函数中,分离Phoenix默认为您附加的遥测处理程序。 (调用:telemetry.list_handlers([])
查看所有附加的侦听器。)def start(_type, _args) do # ... # vvv ADD THESE vvv :ok = :telemetry.detach({Phoenix.Logger, [:phoenix, :socket_connected]}) :ok = :telemetry.detach({Phoenix.Logger, [:phoenix, :channel_joined]}) :ok = :telemetry.detach({Phoenix.Logger, [:phoenix, :router_dispatch, :start]}) # ... Supervisor.start_link(children, opts)
在
lib/my_app_web/endpoint.ex
中,注释掉Plug.Telemetry
插件。在
lib/my_app_web/endpoint.ex
中,在 Plug.Session 之前添加此自定义插件:# One-line request logging. Must come before the session & router plugs. plug MyAppWeb.RequestLogger
最后加上
lib/my_app_web/plugs/request_logger.ex
。 (相应地调整细节;此实现假定 logged-in 用户结构存储在conn.assigns.current_user
中):# One-line full request logging inspired by Plug.Logger. # See https://github.com/elixir-plug/plug/blob/v1.8.0/lib/plug/logger.ex # Need to restart the server after updating this file. defmodule MyAppWeb.RequestLogger do require Logger @behaviour Plug def init(opts), do: opts def call(conn, _opts) do start_time = System.monotonic_time() Plug.Conn.register_before_send(conn, fn(conn) -> # We don't want passwords etc. being logged params = inspect(Phoenix.Logger.filter_values(conn.params)) # Log any important session data eg. logged-in user user = conn.assigns[:current_user] user_string = if user, do: "#{user.id} (#{user.name})", else: "(none)" # Note redirect, if any redirect = Plug.Conn.get_resp_header(conn, "location") redirect_string = if redirect != [], do: " redirected_to=#{redirect}", else: "" # Calculate time taken (in ms for consistency) stop_time = System.monotonic_time() time_us = System.convert_time_unit(stop_time - start_time, :native, :microsecond) time_ms = div(time_us, 100) / 10 Logger.log(:info, "■ method=#{conn.method} path=#{conn.request_path} params=#{params} "<> "user=#{user_string} status=#{conn.status}#{redirect_string} duration=#{time_ms}ms" ) conn end) end end
重新启动您的服务器,您现在应该只看到每个请求的一个日志行,格式如下:
2019-06-09 18:18:51.410 [info] ■ [PUT /manage/projects/7qDjSk/prompts/3tUrF9] params=%{"project_uuid" => "7qDjSk", "prompt" => %{"html" => "<div>Test question 3</div>"}, "prompt_uuid" => "3tUrF9"} user=1 (Topher Hunt) status=302 redirected_to=/manage/projects/7qDjSk duration=21ms
(注意:另一种更 best-practice 的方法是 :telemetry.attach
到 Phoenix 已经发出的 [:phoenix, :router_dispatch, :stop]
事件。这提供了我们需要的所有数据;见the Phoenix.Endpoint docs 了解更多详情。)
有用的参考资料:
还有这个,如果你想要JSON输出:https://github.com/Nebo15/logger_json/tree/master/lib/logger_json