logging - Elixir /凤凰/Ecto : How to customize SQL query log format?

标签 logging elixir ecto

在我的 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]

但我想对这种格式做一些调整:

  • 每个 sql 查询产生两行日志输出。将所有这些信息放在一行中对我来说很重要,因为这样可以更容易地在日志管理服务中查找事件,例如 Papertrail .
  • 理想情况下,我想去除字段名称周围的引号,以便查询更易于直观扫描。

如何自定义 Ecto sql 查询日志的格式?

最佳答案

似乎没有自定义 Ecto 的日志格式这样的东西;相反,我需要禁用内置日志记录并编写我自己的日志记录功能。 但这在 Ecto v2 和 Ecto v3 中的工作方式非常不同。


外链 v2

config.exs 中,配置 MyApp.Repo 以使用新的自定义记录器函数。该函数可以存在于任何地方,但在我的例子中,我将它放在 MyApp.Repo.log_query/2 中:

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

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

就是这样!确保您的日志级别设置正确,重新启动您的应用程序,您应该会看到所有 Ecto 查询都以这种新格式而不是旧格式记录。


外链v3

Ecto v3 鼓励您使用 telemetry events而不是那些令人讨厌的旧配置内容。

lib/my_app/application.ex MyApp.Application.start/2 中,您需要设置遥测事件。在 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, %{})

然后定义您的 Telemetry 模块,该模块目前只有一个事件处理程序。我将我的保存在 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

config/config.exs 中,配置 MyApp.Repo 以禁用标准 Ecto 日志记录:

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

就是这样!确保您的日志级别设置正确,重新启动您的应用程序,您应该会看到所有 Ecto 查询都以这种新格式而不是旧格式记录。

关于logging - Elixir /凤凰/Ecto : How to customize SQL query log format?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56601417/

相关文章:

logging - 如何解决特定的循环依赖: DAL & Logging

erlang - mix deps.get 失败(似乎缺少 ssl?)

zlib - 如何在 Elixir 中 Zlib 膨胀字节列表?

elixir - Elixir 中如何将时间戳转换为日期时间?

sql - 带有条件 where 的 Ecto 片段子查询

asp.net - Microsoft.Extensions.Logging 如何在完整的 .net 框架中工作?

java - 你觉得 java.util.logging 足够了吗?

elixir - 在后台发出 http 请求并更新客户端

elixir - 是否可以编写一个联合多个表的 Ecto 查询,而无需编写原始 SQL?

java - java.util.logging.Filehandler 更改输出文件时调用方法