Current section
Files
Jump to
Current section
Files
lib/new_relixir/plug/instrumentation.ex
defmodule NewRelixir.Plug.Instrumentation do
@moduledoc """
Utility methods for instrumenting parts of an Ecto app.
"""
import NewRelixir.Utils
alias NewRelixir.{CurrentTransaction, Transaction}
@doc """
Instruments a database call and records the elapsed time.
* `action` is the name of the repository function being instrumented.
* `queryable` is the `Queryable` being passed to the repository.
* `opts` is a keyword list of overrides to parts of the recorded transaction name.
* `f` is the function to be instrumented.
By default, the query name will be inferred from `queryable` and `action`. This
can be overriden by providing a `:query` option in `opts`.
"""
@spec instrument_db(atom, Ecto.Queryable.t, Keyword.t, fun) :: any
def instrument_db(action, queryable, opts, f) do
{elapsed, result} = :timer.tc(f)
opts
|> put_model(queryable)
|> put_action(action)
|> record(elapsed)
result
end
defp put_model(opts, queryable) do
case Keyword.fetch(opts, :model) do
{:ok, _} -> opts
:error ->
if model = infer_model(queryable) do
Keyword.put(opts, :model, model)
else
opts
end
end
end
defp put_action(opts, action) do
Keyword.put_new(opts, :action, action)
end
defp infer_model(%{__struct__: model_type, __meta__: %Ecto.Schema.Metadata{}}) do
short_module_name(model_type)
end
defp infer_model(%{data: data}) do #ecto 2.0
infer_model(data)
end
defp infer_model(%Ecto.Query{from: {_, model_type}}) do
short_module_name(model_type)
end
defp infer_model(%Ecto.Query{}) do
nil
end
defp infer_model([first_queryable | _others]) do
infer_model(first_queryable)
end
defp infer_model(queryable) do
infer_model(Ecto.Queryable.to_query(queryable))
end
defp record(opts, elapsed) do
case CurrentTransaction.get() do
{:ok, transaction} ->
query = get_query(opts)
Transaction.record_db(transaction, query, elapsed)
error ->
error
end
end
defp get_query(opts) do
case Keyword.fetch(opts, :query) do
{:ok, value} ->
value
:error ->
case {Keyword.fetch(opts, :model), Keyword.fetch(opts, :action)} do
{{:ok, model}, {:ok, action}} ->
"#{model}.#{action}"
_ ->
"SQL"
end
end
end
end