简体   繁体   English

Elixir / Phoenix:如何自定义 HTTP 请求日志格式?

[英]Elixir / Phoenix: How to customize HTTP request log format?

By default, my Phoenix apps log basic information about each HTTP request across ~ 5 lines of log output.默认情况下,我的 Phoenix 应用程序会在大约 5 行日志输出中记录有关每个 HTTP 请求的基本信息。 As long as I've set my log level to :debug , I can see each request's method, path, controller & action, params, response code, and duration:只要我将日志级别设置为: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

That's a great starting point.这是一个很好的起点。 But I'd like to customize the app to log all of this info on one line, which is helpful eg.但我想自定义应用程序以在一行上记录所有这些信息,这很有帮助,例如。 when sifting through large amounts of log output in a tool like Papertrail .Papertrail 等工具中筛选大量日志输出时。 In particular I'd like each request to show up in a format like this:特别是我希望每个请求都以这样的格式显示:

[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

In the Phoenix.Controller docs I see I can configure the log level for the Phoenix controller logging, or disable it altogether, but I don't see a way to customize the format.Phoenix.Controller 文档中,我看到我可以为 Phoenix 控制器日志配置日志级别,或者完全禁用它,但我没有看到自定义格式的方法。 How can I do this?我怎样才能做到这一点?

This isn't a matter of customizing output, rather it's a matter of 1) disabling the default request-related log statements (by detaching the relevant :telemetry handlers) then 2) adding a new plug to log the format I want.这不是自定义输出的问题,而是 1) 禁用与请求相关的默认日志语句(通过分离相关的:telemetry处理程序)然后 2) 添加一个新插件来记录我想要的格式。

Here's how I did it:这是我如何做到的:

  • In application.ex , in the start/2 function, detach the telemetry handlers that Phoenix attaches for you by default.application.exstart/2函数中,分离 Phoenix 默认为您附加的遥测处理程序。 (Call :telemetry.list_handlers([]) to see all attached listeners.) (调用: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)
  • In lib/my_app_web/endpoint.ex , comment out the Plug.Telemetry plug.lib/my_app_web/endpoint.ex ,注释掉Plug.Telemetry插件。

  • In lib/my_app_web/endpoint.ex , add this custom plug just before Plug.Session:lib/my_app_web/endpoint.ex ,在 Plug.Session 之前添加这个自定义插件:

     # One-line request logging. Must come before the session & router plugs. plug MyAppWeb.RequestLogger
  • Finally, add lib/my_app_web/plugs/request_logger.ex .最后,添加lib/my_app_web/plugs/request_logger.ex (Adjust the details accordingly; this implementation assumes the logged-in user struct is stored in conn.assigns.current_user ): (相应地调整细节;此实现假设登录用户结构存储在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
  • Restart your server, and you should now see just one log line per request, formatted like this:重新启动您的服务器,您现在应该看到每个请求只有一个日志行,格式如下:

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

(Note: Another, more best-practice approach would be to :telemetry.attach to the [:phoenix, :router_dispatch, :stop] event that Phoenix is already emitting. This provides all the data we'd need; see the Phoenix.Endpoint docs for more detail.) (注意:另一种更佳实践的方法是:telemetry.attach到 Phoenix 已经发出的[:phoenix, :router_dispatch, :stop]事件。这提供了我们需要的所有数据;参见Phoenix。有关更多详细信息,请参阅端点文档。)

Useful references:有用的参考:

还有这个,如果你想要 JSON 输出: https : //github.com/Nebo15/logger_json/tree/master/lib/logger_json

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM