Elixir Features

Note: These docs do not cover out of the box features of the agents, such as metric and trace collection.

Highly Recommended: While we strive for a minimal setup experience, there are a few features that may require additional setup: Deploy Tracking, Request Queueing and Custom Context.

Deploy Tracking

Scout can track deploys, making it easier to correlate changes in your app to performance. To enable deploy tracking, first ensure you are on the latest version of scout_apm. See our upgrade instructions.

Scout identifies deploys via the following:

  1. A revision_sha config setting.
  2. A SCOUT_REVISION_SHA environment variable equal to the SHA of your latest release.
  3. If you are using Heroku, enable Dyno Metadata. This adds a HEROKU_SLUG_COMMIT environment variable to your dynos, which Scout then associates with deploys.

Request Queuing

Our Elixir integration can measure the time it takes a request to reach your application from farther upstream (a load balancer or web server). This appears in Scout as “Request Queueing” and provides an indication of your application’s capacity. Large request queueing time is an indication that your app needs more capacity.

Please view request queueing section to learn how to get these insights.

Note: For Elixir, we currently only support the following two headers: x-queue-start and x-request-start, and we don’t support msec – or decimal millisecond. Example of valid header: x-request-start: "1234567890123"

Custom Context

Context lets you see the forest from the trees. For example, you can add custom context to answer critical questions like:

User Context

For context used to identify users (ex: id):

ScoutApm.add_user(key, value)

Examples:

ScoutApm.Context.add_user(:id, user.id)

General Context

ScoutApm.Context.add(key, value)

Examples:

ScoutApm.Context.add(:account, account.id)
ScoutApm.Context.add(:monthly_spend, account.monthly_spend)

Default Context

Scout reports the Request URI and the user’s remote IP Address by default.

Context Value Types Context values can be any of the following types:

Context Key Restrictions

Context keys can be an Atom or String with only printable characters. Custom context keys may contain alphanumeric characters, dashes, and underscores. Spaces are not allowed. Attempts to add invalid context will be ignored.

PII

To best help protect you data, we suggest using ids instead of explicit names and emails

Custom Instrumentation

You can extend Scout to record additional types of transactions (background jobs, for example) and time the execution of code that fall outside our auto instrumentation.

For full details on instrumentation functions, see our ScoutApm. Tracing Hex docs.

Transactions & Timing

Scout’s instrumentation is divided into 2 areas:

1. Transactions: these wrap around a flow of work, like a web request or a GenServer call. The UI groups data under transactions. Use the deftransaction/2 macro or wrap blocks of code with the transaction/4 macro.

2. Timing: these measure individual pieces of work, like an HTTP request to an outside service or an Ecto query, and displays timing information within a transaction trace. Use the deftiming/2 macro or the timing/4 macro.

Instrumenting transactions

deftransaction Macro Example

Replace your function def with deftransaction to instrument it.

You can override the name and type by setting the @transaction_opts attribute right before the function.

defmodule YourApp.Web.RoomChannel do
use Phoenix.Channel import ScoutApm.Tracing

# Will appear under "Web" in the UI, named "YourApp.Web.RoomChannel.join".
@transaction_opts [type: "web"]
deftransaction join("topic:html", _message, socket) do
  {:ok, socket}
end

# Will appear under "Background Jobs" in the UI, named "RoomChannel.ping".
@transaction_opts [type: "background", name: "RoomChannel.ping"]
deftransaction handle_in("ping", %{"body" => body}, socket) do
  broadcast! socket, "new_msg", %{body: body} {:noreply, socket}
end

transaction/4 Example

Wrap the block of code you’d like to instrument with transaction/4:

import ScoutApm.Tracking def
  do_async_work do Task.start(fn ->
    # Will appear under "Background Jobs" in the UI, named "Do Work".
    transaction(:background, "Do Work") do
      # Do work...
    end
  end)
end

See the ScoutApm.Tracing Hexdocs for details on instrumenting transactions.

Timing functions and blocks of code

deftiming Macro Example

Replace your function def with deftiming to instrument it. You can override the name and category by setting the @timing_opts attribute right before the function.

defmodule Searcher do
 import ScoutApm.Tracing

 # Time associated with this function will appear under "Hound" in timeseries charts.
 # The function will appear as `Hound/open_search` in transaction traces.
 @timing_opts [category: "Hound"] deftiming open_search(url) do
  navigate_to(url)
 end

 # Time associated with this function will appear under "Hound" in timeseries charts.
 # The function will appear as `Hound/homepage` in transaction traces.

 @timing_opts [category: "Hound", name: "homepage"]
 deftiming open_homepage(url) do
   navigate_to(url)
end

timing/4 Example

Wrap the block of code you’d like to instrument with timing/4:

defmodule PhoenixApp.PageController do
use PhoenixApp.Web, :controller import ScoutApm.Tracing
def index(conn, _params) do
  timing("Timer", "sleep") do
    :timer.sleep(3000)
  end
  render conn, "index.html"
end

See the ScoutApm.Tracing Hexdocs for details on timing functions and blocks of code. #### Limits on category arity We limit the number of unique categories that can be instrumented. Tracking too many unique category can impact the performance of our UI. Do not dynamically generate categories in your instrumentation (ie timing("user_#{user.id}", "generate", do: do_work()) as this can quickly exceed our rate limits.

Adding a description

Call ScoutApm.Tracing.update_desc/1 to add relevant information to the instrumented item. This description is then viewable in traces. An example:

timing("HTTP", "GitHub_Avatar") do
  url = "https://github.com/#{user.id}.png"
  update_desc("GET #{url}")
  HTTPoison.get(url)
end

Tracking

Already executed time Libraries like Ecto log details on executed queries. This includes timing information. To add a trace item for this, use ScoutApm.Tracing.track. An example:

defmodule YourApp.Mongo.Repo do
  use Ecto.Repo # Scout instrumentation of Mongo queries. These appear in traces as "Ecto/Read", "Ecto/Write", etc.

  def log(entry) do
    ScoutApm.Tracing.track( "Ecto", query_name(entry), entry.query_time, :microseconds )
    super entry
  end
end

In the example above, the metric will appear in traces as Ecto/#{query_time(entry)}. On timeseries charts, the time will be allocated to Ecto. See the scout_apm hex docs for more information on track/.

Server Timing

View performance metrics (time spent in Controller, Ecto, etc) for each of your app’s requests in Chrome’s Developer tools with the plug_server_timing package. Production-safe.

server timing

For install instructions and configuration options, see plug_server_timing on GitHub.

ARM Support

ARM and graviton Support

We now have support for ARM and graviton.