Current section

Files

Jump to
commanded_audit_middleware lib middleware auditing.ex
Raw

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(: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{
assigns: %{occurred_at: occurred_at},
causation_id: causation_id,
correlation_id: correlation_id,
command: command,
command_uuid: command_uuid,
metadata: metadata} = pipeline)
do
audit = %CommandAudit{
command_uuid: command_uuid,
causation_id: causation_id,
correlation_id: correlation_id,
occurred_at: occurred_at,
command_type: Atom.to_string(command.__struct__),
data: serialize(command),
metadata: serialize(metadata),
}
Repo.insert!(audit)
pipeline
end
defp success(%Pipeline{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{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)
# 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