Current section
Files
Jump to
Current section
Files
lib/middleware/auditing.ex
defmodule Commanded.Middleware.Auditing do
@behaviour Commanded.Middleware
alias Commanded.Middleware.Auditing.CommandAudit
alias Commanded.Middleware.Auditing.Repo
alias Commanded.Middleware.Pipeline
import Pipeline
import Ecto.Query, only: [from: 2]
def before_dispatch(%Pipeline{} = pipeline) do
pipeline
|> assign(:command_uuid, UUID.uuid4)
|> assign(:occurred_at, DateTime.utc_now)
|> audit()
end
def after_dispatch(%Pipeline{} = pipeline) do
pipeline
|> success
end
def after_failure(%Pipeline{} = pipeline) do
pipeline
|> failure
end
defp audit(%Pipeline{command: command, assigns: %{command_uuid: command_uuid, occurred_at: occurred_at} = assigns} = pipeline) do
audit = %CommandAudit{
command_uuid: command_uuid,
occurred_at: occurred_at,
command_type: Atom.to_string(command.__struct__),
data: serialize(command),
metadata: serialize(assigns),
}
Repo.insert!(audit)
pipeline
end
defp success(%Pipeline{assigns: %{command_uuid: command_uuid}} = pipeline) do
command_uuid
|> query_by_command_uuid
|> Repo.update_all(set: [
success: true,
execution_duration_usecs: delta(pipeline),
])
pipeline
end
defp failure(%Pipeline{assigns: %{command_uuid: command_uuid}} = pipeline) do
command_uuid
|> query_by_command_uuid
|> Repo.update_all(set: [
success: false,
execution_duration_usecs: delta(pipeline),
error: extract(pipeline, :error),
error_reason: extract(pipeline, :error_reason),
])
pipeline
end
defp extract(%Pipeline{assigns: assigns}, key) do
case Map.get(assigns, key) do
nil -> nil
value -> inspect(value)
end
end
defp query_by_command_uuid(command_uuid) do
from audit in CommandAudit,
where: audit.command_uuid == ^command_uuid
end
defp serialize(term), do: serializer().serialize(term)
defp serializer do
Application.get_env(:commanded_audit_middleware, :serializer)
end
# calculate the delta, in usecs, between command occurred at date/time and now
defp delta(%Pipeline{assigns: %{occurred_at: occurred_at}}) do
now_usecs = DateTime.utc_now |> DateTime.to_unix(:microseconds)
occurred_at_usecs = occurred_at |> DateTime.to_unix(:microseconds)
now_usecs - occurred_at_usecs
end
end