StatetraceElixir

Elixir integration for https://www.statetrace.com

Read the Statetrace Tutorial for more information.

Installation

The package can be installed by adding statetrace_elixir to your list of dependencies in mix.exs:

def deps do
  [
    {:statetrace_elixir, "~> 0.2.0"}
  ]
end

After the packages are installed you must create a database migration to add the statetrace_annotations table to your database:

mix ecto.gen.migration add_statetrace_annotations_table

Open the generated migration in your editor and call the up and down functions on StatetraceElixir.Migrations:

defmodule MyApp.Repo.Migrations.AddStatetraceAnnotationsTable do
  use Ecto.Migration

  def up do
    StatetraceElixir.Migrations.up()
  end

  # We specify `version: 1` in `down`, ensuring that we'll roll all the way back down if
  # necessary, regardless of which version we've migrated `up` to.
  def down do
    StatetraceElixir.Migrations.down(version: 1)
  end
end

New versions may require additional migrations, however, migrations will never change between versions and they are always idempotent.

Now, run the migration to create the table:

mix ecto.migrate

Next we need to annotate your http requests' transactions. Wrap &action/2 in your controllers in a transaction and annotate it.

Its easiest to add this to <YourProject>Web

defmodule <YourProject>Web do
  def controller do
    quote do
      use Phoenix.Controller, namespace: <YourProject>Web

      import Plug.Conn
      import <YourProject>Web.Gettext
      alias <YourProject>Web.Router.Helpers, as: Routes
      alias StatetraceElixir.Annotations

      defp current_actor(conn) do
        # Should return nil | %{id: String.t | nil, full_name: String.t | nil, avatar: String.t | nil}
        conn.assigns.current_user 
      end

      def action(conn, _) do
        args = [conn, conn.params]

        with {_, response} <-
               <YourProject>.Repo.transaction(fn ->
                 Annotations.process_conn(conn,
                   get_actor: &current_actor/1,
                   repo: <YourProject>.Repo
                 )

                 apply(__MODULE__, action_name(conn), args)
               end) do
          response
        end
      end
    end
  end
end

The available options for process_conn are

  • :get_action_url (expects nil or string)
  • :get_action_method (expects nil or string)
  • :get_action_meta (expects nil or map)
  • :get_session_meta (expects nil or map)
  • :get_actor (expects nil or %{id: String.t | nil, full_name: String.t | nil, avatar: String.t | nil})

All of which are functions that take a conn.