简体   繁体   English

Elixir / Phoenix / Ecto:如何自定义 SQL 查询日志格式?

[英]Elixir / Phoenix / Ecto: How to customize SQL query log format?

In my Phoenix/Ecto apps, when I set log level to :debug , I see helpful log entries for each SQL query issued by Ecto, like this:在我的 Phoenix/Ecto 应用程序中,当我将日志级别设置为:debug ,我会看到 Ecto 发出的每个 SQL 查询的有用日志条目,如下所示:

[debug] QUERY OK source="users" db=1.9ms
SELECT u0."id", u0."full_name", u0."email", u0."uuid", u0."auth0_uid", u0."last_signed_in_at", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1) LIMIT 1 [1]
[debug] QUERY OK source="projects" db=11.8ms
SELECT p0."id", p0."name", p0."uuid", p0."settings", p0."inserted_at", p0."updated_at" FROM "projects" AS p0 WHERE (p0."uuid" = $1) LIMIT 1 ["7qDjSk"]
[debug] QUERY OK source="project_admin_joins" db=1.9ms
SELECT p0."id", p0."project_id", p0."admin_id", p0."inserted_at", p0."updated_at", p0."project_id" FROM "project_admin_joins" AS p0 WHERE (p0."project_id" = $1) ORDER BY p0."project_id" [2]

But I'd love to tweak a couple things about this format:但我想对这种格式进行一些调整:

  • Each sql query produces two lines of log output.每个 sql 查询产生两行日志输出。 It's important to me to have all this info on a single line, because that makes it much easier to find events in log management services like Papertrail .将所有这些信息放在一行中对我来说很重要,因为这样可以更轻松地在Papertrail等日志管理服务中查找事件。
  • Ideally I'd like to strip out the quotes around the field names so the query is easier to visually scan.理想情况下,我想去掉字段名称周围的引号,以便查询更易于视觉扫描。

How can I customize the format of the Ecto sql query logs?如何自定义 Ecto sql 查询日志的格式?

It looks like there's no such thing as customizing Ecto's logging format;好像没有自定义 Ecto 的日志格式这样的东西; instead I needed to disable the built-in logging and write my own logging function.相反,我需要禁用内置日志记录并编写自己的日志记录功能。 But this works very differently in Ecto v2 versus Ecto v3.但是这在 Ecto v2 和 Ecto v3 中的工作方式非常不同。


Ecto v2 Ecto v2

In config.exs , configure MyApp.Repo to use a new custom logger function.config.exs ,将 MyApp.Repo 配置为使用新的自定义记录器功能。 That function can live wherever, but in my case I've put it in MyApp.Repo.log_query/2 :该函数可以存在于任何地方,但就我而言,我已将其放在MyApp.Repo.log_query/2

config :my_app, MyApp.Repo,
  # ...
  loggers: [{MyApp.Repo, :log_query, []}]

In lib/my_app/repo.ex , define the log_query function: (note: in my case I've hard-coded the :debug log level.)lib/my_app/repo.ex ,定义log_query函数:(注意:在我的例子中,我已经硬编码了:debug日志级别。)

  ...
  require Logger

  # Inspired by https://github.com/elixir-ecto/ecto/blob/v2.2.11/lib/ecto/log_entry.ex
  def log_query(entry) do
    Logger.log(:debug, fn ->
      {ok, _} = entry.result
      source = inspect(entry.source)
      time_us = System.convert_time_unit(entry.query_time, :native, :microsecond)
      time_ms = div(time_us, 100) / 10
      # Strip out unnecessary quotes from the query for readability
      query = Regex.replace(~r/(\d\.)"([^"]+)"/, entry.query, "\\1\\2")
      params = inspect(entry.params, charlists: false)

      "SQL query: #{ok} source=#{source} db=#{time_ms}ms   #{query}   params=#{params}"
    end)
  end

That's it!就是这样! Make sure your log level is set appropriately, restart your app, and you should see all Ecto queries logged in this new format instead of the old one.确保您的日志级别设置正确,重新启动您的应用程序,您应该看到所有 Ecto 查询都以这种新格式而不是旧格式记录。


Ecto v3 Ecto v3

Ecto v3 encourages you to use telemetry events instead of that nasty old config stuff. Ecto v3 鼓励您使用 遥测事件而不是那些讨厌的旧配置内容。

In lib/my_app/application.ex MyApp.Application.start/2 , you need to set up the telemetry event.lib/my_app/application.ex MyApp.Application.start/2 ,需要设置遥测事件。 Add this snippet just before the Supervisor.start_link/2 call:Supervisor.start_link/2调用之前添加这个片段:

    # Subscribe to Ecto queries for logging
    # See https://hexdocs.pm/ecto/Ecto.Repo.html#module-telemetry-events
    # and https://github.com/beam-telemetry/telemetry
    handler = &MyApp.Telemetry.handle_event/4
    :ok = :telemetry.attach("my_app-ecto", [:my_app, :repo, :query], handler, %{})

Then define your Telemetry module which for now will only have this one event handler.然后定义您的 Telemetry 模块,它现在只有一个事件处理程序。 I saved mine in lib/my_app/telemetry.ex :我将我的保存在lib/my_app/telemetry.ex

defmodule MyApp.Telemetry do
  require Logger

  # Thanks to https://hexdocs.pm/ecto/Ecto.Repo.html#module-telemetry-events
  def handle_event([:my_app, :repo, :query], measurements, metadata, _config) do
    Logger.log(:debug, fn ->
      {ok, _} = metadata.result
      source = inspect(metadata.source)
      time = div(measurements.query_time, 100_000) / 10
      # Strip out unnecessary quotes from the query for readability
      query = Regex.replace(~r/(\d\.)"([^"]+)"/, metadata.query, "\\1\\2")
      params = inspect(metadata.params, charlists: false)

      "SQL query: #{ok} source=#{source} db=#{time}ms   #{query}   params=#{params}"
    end)
  end
end

In config/config.exs , configure MyApp.Repo to disable the standard Ecto logging:config/config.exs ,配置 MyApp.Repo 以禁用标准的 Ecto 日志记录:

config :my_app, MyApp.Repo,
  # ...
  log: false

That's it!就是这样! Make sure your log level is set appropriately, restart your app, and you should see all Ecto queries logged in this new format instead of the old one.确保您的日志级别设置正确,重新启动您的应用程序,您应该看到所有 Ecto 查询都以这种新格式而不是旧格式记录。

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

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