Qtrace (qtrace v1.0.0)

View Source

Quick function latency analysis and visualization based on Erlang tracing.

Qtrace traces function calls and collects latency measurements. Uses histogram-based aggregation to provide quantile analysis (P50, P95, P99) and terminal-based visualization of performance distributions.

Usage

session = Qtrace.start_session(:all)
Qtrace.trace_function(session, MyApp, :my_function, 2)
Qtrace.trace_function(session, MyApp, :another_function, 1)

# ... run your code ...

Qtrace.plot_all_histograms(session)

# Getting p10
Qtrace.get_quantile(session, 0.10, MyApp, :my_function, 2)

Example output

Latency Histogram: Qtrace.Demo.web_request/0
================================================================================
            0              13             26             39             52
      5.9ms  │███ (3)
      6.9ms  │█ (1)
      8.1ms  │██ (2)
      10.3ms │█ (1)
      11.2ms │██████ (5)
      12.1ms │█████ (4)
      13.2ms │███ (3)
      14.2ms │███████ (6)
      15.4ms │████████████████ (14)
      16.7ms │█████████████████ (15)
      18.1ms │████████████████████ (17)
      19.6ms │█████████████████████████████████ (29)
      21.3ms │██████████████████████████████████████████████████████████ (50)
      23.0ms │██████████████████████████████████████████ (36)
      24.9ms │███████████████████████████████████████████████ (41)
      27.0ms │████████████████████████████████████████████████████████████ (52)
      29.3ms │█████████████████████████████████████████████████████████ (49)
      31.7ms │███████████████████████████████████████████████████████████ (51)
      34.4ms │██████████████████████████████████████ (33)
      37.2ms │████████████████████████████████████████ (35)
      40.3ms │████████████████████████ (21)
      43.7ms │███████ (6)
      47.3ms │███ (3)
      51.3ms │██ (2)
    134.0ms  │██ (2)
    157.2ms  │█ (1)
    199.9ms  │█ (1)
    216.6ms  │█████████ (8)
    234.6ms  │██ (2)
    254.2ms  │██ (2)
    275.4ms  │███ (3)
    298.3ms  │██ (2)
    323.2ms  │██ (2)
             └────────────────────────────────────────────────────────────
            0              13             26             39             52
Stats:
  Min: 5.9ms
  Max: 323.2ms
  Samples: 502
  P50: 27.0ms
  P95: 47.3ms
  P99: 275.4ms

Session Management

Tracing is automatically stopped when the trace session gets garbage collected. The trace process may live for a bit longer: it lives for up to two minutes of inactivity.

You can also stop sessions or clean up trace data manually:

Qtrace.stop_session(session) # Stop the trace session
Qtrace.cleanup(session)      # Stop the tracer process that stores the results

Notice that, in some situations, you may need to ensure that the session doesn't get garbage collected to avoid the trace stopping unexpectedly.

Notes

  • Sessions auto-stop when querying results
  • Measurements are in microseconds
  • Buckets have an error of up to 4%

Summary

Functions

Adds processes to an existing tracing session.

Stops the tracer process for a session.

Builds histogram data from traced function measurements.

Gets a quantile from traced function performance data. Returns latency in microseconds.

Displays histograms for all traced functions.

Displays a histogram of latency measurements in the terminal.

Removes processes from an existing tracing session.

Starts a new tracing session.

Stops a tracing session. Trace results remain available until cleanup.

Enables tracing for a specific function.

Functions

add_processes(session, processes)

@spec add_processes(Qtrace.Session.t(), :all | :existing | :new | pid()) ::
  non_neg_integer()

Adds processes to an existing tracing session.

Example

session = Qtrace.start_session(:existing)
Qtrace.add_processes(session, :new)  # Now traces existing + new processes

cleanup(session)

@spec cleanup(Qtrace.Session.t()) :: :ok

Stops the tracer process for a session.

Example

session = Qtrace.start_session(:all)
# ... do tracing work ...
Qtrace.cleanup(session)  # Immediately stop the tracer

get_histogram(session, module, function, arity)

@spec get_histogram(Qtrace.Session.t(), module(), atom(), non_neg_integer()) ::
  Qtrace.Histogram.t() | nil

Builds histogram data from traced function measurements.

Returns a %Qtrace.Histogram{} struct or nil if no data available.

get_quantile(session, quantile, module, function, arity)

@spec get_quantile(
  Qtrace.Session.t(),
  quantile :: float(),
  module(),
  function_name :: atom(),
  arity()
) :: number() | nil

Gets a quantile from traced function performance data. Returns latency in microseconds.

Examples

# Get median latency (P50)
p50 = Qtrace.get_quantile(session, 0.5, MyApp, :my_function, 1)

# Get 95th percentile
p95 = Qtrace.get_quantile(session, 0.95, MyApp, :my_function, 1)

plot_all_histograms(session, opts \\ [])

@spec plot_all_histograms(
  Qtrace.Session.t(),
  keyword()
) :: :ok

Displays histograms for all traced functions.

Options

  • :width - Width of the histogram bars (default: 60)

plot_histogram(session, module, function, arity, opts \\ [])

@spec plot_histogram(
  Qtrace.Session.t(),
  module(),
  atom(),
  non_neg_integer(),
  keyword()
) :: :ok

Displays a histogram of latency measurements in the terminal.

Options

  • :width - Width of the histogram bars (default: 60)

Example

Qtrace.plot_histogram(session, MyApp, :my_function, 1)

remove_processes(session, processes)

@spec remove_processes(Qtrace.Session.t(), :all | :existing | :new | pid()) ::
  non_neg_integer()

Removes processes from an existing tracing session.

Example

session = Qtrace.start_session(:all)
Qtrace.remove_processes(session, :new)  # Stop tracing new processes

start_session(processes)

@spec start_session(:all | :existing | :new | pid()) :: Qtrace.Session.t()

Starts a new tracing session.

Parameters

  • processes - Which processes to trace (:all, :existing, :new, or a pid())

Returns

Returns a Qtrace.Session.t() struct containing the session details. If this struct is garbage collected, the trace stops.

Examples

# Trace all processes
session = Qtrace.start_session(:all)

# Trace only existing processes with a custom name
session = Qtrace.start_session(:existing, :my_trace_session)

# Trace a specific process
session = Qtrace.start_session(self())

stop_session(session)

@spec stop_session(Qtrace.Session.t()) :: Qtrace.Session.t()

Stops a tracing session. Trace results remain available until cleanup.

Example

session = Qtrace.start_session(:all)
# ... do tracing work ...
Qtrace.stop_session(session)

trace_function(session, module, function, arity)

@spec trace_function(Qtrace.Session.t(), module(), atom(), non_neg_integer()) ::
  non_neg_integer()

Enables tracing for a specific function.

Example

session = Qtrace.start_session(:all)
Qtrace.trace_function(session, Enum, :map, 2)

# Now all calls to Enum.map/2 will be traced

Restrictions

Some modules cannot be traced: