Elixir / Phoenix / Ecto: Как настроить формат журнала SQL-запросов? - PullRequest
1 голос
/ 14 июня 2019

В моих приложениях Phoenix / Ecto, когда я устанавливаю уровень журнала на :debug, я вижу полезные записи журнала для каждого SQL-запроса, выданного Ecto, например:

[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?

1 Ответ

1 голос
/ 14 июня 2019

Похоже, что нет такой вещи, как настройка формата регистрации в Ecto; вместо этого мне нужно было отключить встроенную регистрацию и написать свою собственную функцию регистрации. Но в Ecto v2 и Ecto v3 все работает иначе.


Ecto 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, зарегистрированные в этом новом формате вместо старого.


Ecto v3

Ecto v3 рекомендует вам использовать события телеметрии вместо этих неприятных старых настроек.

В 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, %{})

Затем определите свой модуль телеметрии, который пока будет иметь только один обработчик событий. Я спас свой в 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, зарегистрированные в этом новом формате вместо старого.

...