scout_apm v0.4.4 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. Use
@transaction
module attributes and thetransaction/4
macro. - Timing: these measure individual pieces of work, like an HTTP request to an outside service or an Ecto query. Use
@timing
module attributes and thetiming/4
macro.
Recording transactions
There are 2 ways to define transactions:
deftransaction
macro- Wrapping blocks of code with the
transaction/4
macro.
Deprecated:
@transaction
module attributes
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
Module Attribute Example
This is deprecated due to a number of gotchas around the macro that implements this.
The deftransaction
macro more reliably sets up the instrumentation.
defmodule CampWaitlist.Web.HtmlChannel do
use Phoenix.Channel
use ScoutApm.Tracing
# Will appear under "Web" in the UI, named "CampWaitlist.Web.HtmlChannel.join".
@transaction(type: "web")
def join("topic:html", _message, socket) do
{:ok, socket}
end
We treat this as a web
transaction as it impacts the user experience.
An example treating a GenServer function as a background job:
defmodule CampWaitlist.AvailChecker do
use GenServer
use ScoutApm.Tracing
# Will appear under "Background Jobs" in the UI, named "CampWaitlist.AvailChecker.handle_call".
@transaction(type: "background")
def handle_call({:check, campground}, _from, state) do
# Do work...
end
# Will appear under "Background Jobs" in the UI, named "AvailChecker.status".
@transaction(type: "background", name: "AvailChecker.status")
def handle_call({:status, campground}, _from, state) do
# Do work...
end
Timing Code
There are 2 ways to time the execution of code:
deftiming
macro- Wrapping blocks of code with the
timing/4
macro.
Deprecated:
@timing
module attributes
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
Module Attribute Example
This is deprecated due to a number of gotchas around the macro that implements this.
The deftracing
macro more reliably sets up the instrumentation.
defmodule Searcher do
use 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(category: "Hound")
def 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(category: "Hound", name: "search")
def 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
Link to this section Summary
Functions
Times the execution of the given block
of code, labeling it with category
and name
within Scout
Adds an timing entry of duration value
with units
, labeling it with category
and name
within Scout
Creates a transaction of type
(either web
or background
) with the given name
that should be displayed
in the UI for the provided code block
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 block
of code, labeling it with category
and name
within Scout.
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
def index(conn, _params) do
timing("Timer", "sleep") do
:timer.sleep(3000)
end
render conn, "index.html"
end
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.
Creates a transaction of type
(either web
or background
) with the given name
that should be displayed
in the UI for the provided code block
.
Example Usage
import ScoutApm.Tracking
def do_async_work do
Task.start(fn ->
transaction(:background, "do_work") do
# Do work...
end
end)
end
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