Scout Elixir Performance Monitoring Agent
scout_apm monitors the performance of Elixir applications in production and provides an in-browser profiler during development. Metrics are
reported to Scout, a hosted application monitoring service.
Monitoring Usage
- Signup for a free Scout account.
- Follow our install instructions within the UI.
See our docs for detailed information.
DevTrace (Development Profiler) Usage
DevTrace, Scout's in-browser development profiler, may be used without signup.
To use:
- Follow the same installation steps as monitoring, but skip downloading the config file.
-
In your
config/dev.exsfile, add:# config/dev.exs config :scout_apm, dev_trace: true - Restart your app.
- Refresh your browser window and look for the speed badge.
Instrumentation
See our docs for information on libraries we auto-instrument (like Phoenix controller-actions) and guides for instrumenting Phoenix channels, Task, HTTPoison, GenServer, and more.
Supported Template Engines
Scout APM automatically instruments the following Phoenix template engines:
- EEx (
.eex) - Standard Embedded Elixir templates - ExS (
.exs) - ExScript templates - HEEx (
.heex) - HTML-aware Embedded Elixir (requiresphoenix_live_view ~> 0.17) - Slime (
.slim,.slime) - Slim-like templates (requiresphoenix_slime)
Template engines are enabled automatically based on your project's dependencies. To use Scout's instrumented engines, add to your config/config.exs:
config :phoenix, :template_engines,
eex: ScoutApm.Instruments.EExEngine,
exs: ScoutApm.Instruments.ExsEngine,
heex: ScoutApm.Instruments.HEExEngine # Only if phoenix_live_view is installedError Tracking
Scout APM captures errors automatically and allows manual error capture.
Automatic Error Capture
Errors are automatically captured from:
- Phoenix controller exceptions (via telemetry)
- LiveView exceptions (mount, handle_event, handle_params)
- Oban job failures
-
Code wrapped in
transactionblocks
To enable Phoenix router-level error capture, add to your application startup:
# In your application.ex start/2
def start(_type, _args) do
ScoutApm.Instruments.PhoenixErrorTelemetry.attach()
# ... rest of supervision tree
endManual Error Capture
Capture errors manually with ScoutApm.Error.capture/2:
try do
risky_operation()
rescue
e ->
ScoutApm.Error.capture(e, stacktrace: __STACKTRACE__)
reraise e, __STACKTRACE__
endWith additional context:
ScoutApm.Error.capture(exception,
stacktrace: __STACKTRACE__,
context: %{user_id: user.id},
request_path: conn.request_path,
request_params: conn.params
)Configuration
config :scout_apm,
# Enable/disable error capture (default: true)
errors_enabled: true,
# Exceptions to ignore (default: [])
errors_ignored_exceptions: [Phoenix.Router.NoRouteError],
# Additional parameter keys to filter (default: [])
# Built-in: password, token, secret, api_key, auth, credentials, etc.
errors_filter_parameters: ["credit_card", "cvv"]OTLP Logging
Scout APM can capture Elixir Logger messages, enrich them with request context, and send them to an OpenTelemetry collector via OTLP (OpenTelemetry Protocol).
Setup
- Enable logging in your configuration:
# config/config.exs
config :scout_apm,
logs_enabled: true,
logs_ingest_key: "your-logs-ingest-key" # Or falls back to :key- Attach the log handler in your application startup:
# In your application.ex start/2
def start(_type, _args) do
ScoutApm.Logging.attach()
# ... rest of supervision tree
endAutomatic Context Enrichment
Logs captured within Scout-tracked requests are automatically enriched with:
scout_transaction_id- Unique request identifier for correlationcontroller_entrypoint- Controller action name (e.g., "UsersController#show")job_entrypoint- Background job name (e.g., "Job/EmailWorker")scout_current_operation- Current span type/name (e.g., "Ecto/MyApp.Repo")scout_start_time- Request start time (ISO 8601)scout_end_time- Request end time, if completedscout_duration- Request duration in seconds, if completedscout_tag_{key}- Custom tags fromScoutApm.Context.add/2user.{key}- User context fromScoutApm.Context.add_user/2service.name- Application name from config
Entrypoint and transaction ID attributes persist through the entire request lifecycle, including logs emitted after the Scout transaction completes (e.g., Phoenix endpoint logs).
Example - logs are automatically enriched when inside a Scout-tracked request:
def show(conn, %{"id" => id}) do
user = Repo.get!(User, id)
Logger.info("Fetched user", user_id: id) # Includes Scout context automatically
render(conn, :show, user: user)
endCustom Context
Add custom context that appears in your logs:
ScoutApm.Context.add("feature_flag", "new_checkout")
ScoutApm.Context.add_user("id", current_user.id)
Logger.info("Processing checkout") # Includes scout_tag_feature_flag and user.idConfiguration
config :scout_apm,
# Enable/disable log capture (default: false, opt-in)
logs_enabled: true,
# OTLP collector endpoint
logs_endpoint: "https://otlp.scoutotel.com:4318",
# Authentication key (falls back to :key if not set)
logs_ingest_key: "your-logs-key",
# Minimum log level to capture (default: :info)
logs_level: :info,
# Batching settings
logs_batch_size: 100, # Logs per batch (default: 100)
logs_max_queue_size: 5000, # Max queued logs (default: 5000)
logs_flush_interval_ms: 5_000, # Flush interval in ms (default: 5000)
# Modules to exclude from capture (default: [])
logs_filter_modules: [MyApp.VerboseModule]Programmatic Control
# Attach with custom options
ScoutApm.Logging.attach(level: :warning, filter_modules: [MyApp.Noisy])
# Check if attached
ScoutApm.Logging.attached?() # => true
# Force flush queued logs
ScoutApm.Logging.flush()
# Wait for queue to drain (useful for graceful shutdown)
ScoutApm.Logging.drain(5_000)
# Detach the handler
ScoutApm.Logging.detach()Log Levels
The following Elixir log levels are mapped to OTLP severity:
| Elixir Level | OTLP Severity | OTLP Number |
|---|---|---|
:debug | DEBUG | 5 |
:info | INFO | 9 |
:notice | INFO2 | 11 |
:warning | WARN | 13 |
:error | ERROR | 17 |
:critical | FATAL | 21 |
:alert | FATAL | 21 |
:emergency | FATAL | 21 |
Development
See TESTING.md for information on testing with different template engine configurations.
Releasing
Releases are published to Hex.pm automatically via GitHub Actions when a version tag is pushed.
Standard Release
Update the version in
mix.exs:version: "2.0.0",Commit the version bump:
git commit -am "Bump version to 2.0.0"Tag and push:
git tag v2.0.0 git push origin v2.0.0
The workflow will run tests, verify the tag matches mix.exs, publish to Hex.pm, and create a GitHub Release.
Pre-release / RC Version
Use Elixir's pre-release version format. The tag must match mix.exs exactly.
Update
mix.exs:version: "2.0.0-rc.1",Tag and push:
git tag v2.0.0-rc.1 git push origin v2.0.0-rc.1
Pre-release versions (tags containing -rc, -alpha, -beta, or -dev) are automatically marked as pre-release on GitHub. On Hex.pm, pre-release versions are not installed by default -- users must opt in with {:scout_apm, "~> 2.0.0-rc.1"}.
Requirements
-
A
HEX_API_KEYsecret must be configured in the repository settings. Generate one with:mix hex.user key generate --key-name github-actions