scout_apm v1.0.3 ScoutApm.Tracing
Ths module contains functions to create transactions and time the execution of code. It's used to add instrumentation to an Elixir app.
Scout's instrumentation is divided into 2 areas:
- Transactions: these wrap around a flow of work, like a web request or a GenServer call. The UI groups data under transactions.
- Timing: these measure individual pieces of work, like an HTTP request to an outside service or an Ecto query.
Transaction types
A transaction may be one of two types:
- web: a transaction that impacts the main app experience, like a Phoenix controller action.
- background: a transaction that isn't in the main app flow, like a GenServer call or Exq background job.
If you are instrumenting a stand-alone Elixir app, treat all transactions as `web`. Data from these transactions appear in the App overview charts.
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 CampWaitlist.Web.HtmlChannel do
use Phoenix.Channel
import ScoutApm.Tracing
# Will appear under "Web" in the UI, named "CampWaitlist.Web.HtmlChannel.join".
@transaction_opts [type: "web"]
deftransaction join("topic:html", _message, socket) do
{:ok, socket}
end
Timing Code
deftiming Macro Example
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/search` in transaction traces.
@timing_opts [name: "search", category: "Hound"]
deftiming open_search(url) do
navigate_to(url)
end
Category limitations
We limit the arity of `category`. These are displayed in charts throughput the UI. These should not be generated dynamically and should be limited to higher-level categories (ie Postgres, Redis, HTTP, etc).
use vs. import
To utilize the `deftransaction` and `deftiming` macros, import this module:
defmodule YourModule
import ScoutApm.Tracing
To utilize the module attributes (`@transaction` and `@timing`), inject this module via the `use` macro:
defmodule YourModule
use ScoutApm.Tracing
You can then call `transaction/4` and `timing/4` via the following qualified module name, ie:
ScoutApm.Tracing.timing("HTTP", "GitHub", do: ...)
To drop the full module name, you'll need to use the `import` macro. The following is valid:
defmodule YourModule
use ScoutApm.Tracing
import ScoutApm.Tracing
If you are importing across multiple libraries, it is possible to run into naming collisions. Elixir has documentation around those issues here.
Link to this section Summary
Functions
Times the execution of the given function, labeling it with a `category` and `name` within Scout. The default category is "Custom", and the default name is the fully qualified module, function and arity.
Creates a transaction defaulting to type `background` with the default name being the fully qualified module, function and arity.
Adds an timing entry of duration `value` with `units`, labeling it with `category` and `name` within Scout.
Updates the description for the code executing within a call to `timing/4`. The description is displayed within a Scout trace in the UI.
Link to this section Functions
Times the execution of the given function, labeling it with a `category` and `name` within Scout. The default category is "Custom", and the default name is the fully qualified module, function and arity.
You can override the category and name by setting the `@timing_opts` attribute right before the function.
Within a trace in the Scout UI, the block will appear as `category/name` ie `Images/format_avatar` in traces and will be displayed in timeseries charts under the associated `category`.
Example Usage
defmodule PhoenixApp.PageController do
use PhoenixApp.Web, :controller
import ScoutApm.Tracing
# @timing_opts [category: "Images", name: "format_images"]
deftiming format_avatars(params) do
# Formatting avatars
end
def index(conn, params) do
format_avatars(params)
render conn, "index.html"
end
Creates a transaction defaulting to type `background` with the default name being the fully qualified module, function and arity.
You can override the name and type by setting the `@transaction_opts` attribute right before the function.
Example Usage
import ScoutApm.Tracking
# @transaction_opts [type: "web", name: "name_override"]
deftransaction do_async_work() do
# Do work...
end
internal_layer_type(type)
track(category, name, value, units, opts \\ [])
track( String.t(), String.t(), number(), ScoutApm.Internal.Duration.unit(), keyword() ) :: :ok | :error
Adds an timing entry of duration `value` with `units`, labeling it with `category` and `name` within Scout.
Units
Can be be one of `:microseconds | :milliseconds | :seconds`. These come from `ScoutApm.Internal.Duration.unit/0`.
Example Usage
track("Images", "resize", 200, :milliseconds)
track("HTTP", "get", 300, :milliseconds, desc: "HTTP GET http://api.github.com/")
Opts
A `desc` may be provided to add a detailed background of the event. These are viewable when accessing a trace in the UI.
The duration must have actually occured
This function expects that the `ScoutApm.Internal.Duration` generated by `value` and `units` actually occurs in the transaction. The total time of the transaction IS NOT adjusted.
This naturally occurs when taking the output of Ecto log entries.
Updates the description for the code executing within a call to `timing/4`. The description is displayed within a Scout trace in the UI.
This is useful for logging actual HTTP request URLs, SQL queries, etc.
Example Usage
timing("HTTP", "httparrot") do
update_desc("GET: http://httparrot.herokuapp.com/get")
HTTPoison.get! "http://httparrot.herokuapp.com/get"
end