Set Up Logs

Structured logs allow you to send, view and query logs sent from your applications within Sentry.

With Sentry Structured Logs, you can send text-based log information from your applications to Sentry. Once in Sentry, these logs can be viewed alongside relevant errors, searched by text-string, or searched using their individual attributes.

Logs for Elixir are supported in Sentry Elixir SDK version 12.0.0 and above.

Copied
mix deps.get sentry

Or add it to your mix.exs:

Copied
defp deps do
  [
    {:sentry, "~> 12.0"}
  ]
end

To enable logging, set enable_logs: true in your Sentry configuration:

Copied
# In config/config.exs or config/runtime.exs
config :sentry,
  dsn: "___PUBLIC_DSN___",
  enable_logs: true

When enable_logs is true, the SDK automatically attaches a Sentry.LoggerHandler (registered as :sentry_log_handler) on application startup. No manual handler setup is required.

To configure the minimum log level and other options, use the :logs key:

Copied
config :sentry,
  dsn: "___PUBLIC_DSN___",
  enable_logs: true,
  logs: [
    level: :info,         # minimum log level (default: :info)
    excluded_domains: [], # logger domains to exclude (default: [])
    metadata: []          # metadata keys to include as attributes (default: [])
  ]

Once enable_logs: true is set in your Sentry configuration, you can send logs using Elixir's standard Logger module.

The logs will be sent to Sentry at or above the level configured by the :level option under :logs (default: :info). The supported log levels in Elixir are: debug, info, notice, warning, error, critical, alert, and emergency.

Copied
require Logger

Logger.info("Updated global cache")

Logger.debug("Cache miss for user", user_id: 123)

Logger.warning("Rate limit reached for endpoint", endpoint: "/api/results/")

Logger.error("Failed to process payment", order_id: "or_2342", amount: 99.99)

You can use message templates with positional or named parameters. To use message templates, pass parameters via the :sentry metadata key with :log_parameters:

Copied
# Using named parameters (Elixir format)
Logger.info("User %{name} logged in",
  sentry: [log_parameters: %{name: "Jane Doe"}]
)

# Using positional parameters
Logger.info("User %s logged in",
  sentry: [log_parameters: ["Jane Doe"]]
)

Any metadata passed to Logger calls will be included as log attributes if configured via the :metadata option under :logs. To include all metadata as attributes:

Copied
config :sentry,
  enable_logs: true,
  logs: [
    level: :info,
    metadata: :all  # or [:user_id, :request_id] for specific keys
  ]

Then all metadata will be sent as extra attributes that Sentry Logs UI displays:

Copied
# Here `user_id` and `action` will be sent as extra attributes
Logger.info("User logged in", user_id: 123, action: "create")

If you're using OpenTelemetry with the opentelemetry_logger_metadata package, trace and span IDs will automatically be extracted from your log metadata and included in the log events sent to Sentry. This allows you to correlate logs with traces in the Sentry UI.

Logs are sent to Sentry through Erlang's :logger system via Sentry.LoggerHandler. When enable_logs: true is set in your Sentry configuration, the SDK automatically attaches the handler — no manual setup is needed. Any logs from your application or libraries that use Elixir's Logger or Erlang's :logger will be captured and sent to Sentry at or above the configured level.

The logs behavior is configured globally via the :logs key — not through the handler config map:

Copied
config :sentry,
  enable_logs: true,
  logs: [
    level: :info,
    metadata: [:request_id, :user_id]
  ]

With this configuration, logs at or above :info will be sent to Sentry:

Copied
require Logger

Logger.debug("Debug message")  # Not sent (below :info level)
Logger.info("Info message")    # Sent to Sentry
Logger.warning("Warning")      # Sent to Sentry
Logger.error("Error occurred") # Sent to Sentry

You can exclude specific logger domains from being sent to Sentry using the :excluded_domains option under :logs:

Copied
config :sentry,
  enable_logs: true,
  logs: [
    level: :info,
    excluded_domains: [:ecto, :phoenix]
  ]

To filter or modify logs before they are sent to Sentry, use the before_send_log callback. Return false to skip a log, or return the log event to send it.

Copied
config :sentry,
  dsn: "___PUBLIC_DSN___",
  enable_logs: true,
  before_send_log: fn log_event ->
    # Skip info logs
    if log_event.level == :info do
      false
    else
      log_event
    end
  end

You can also use a module/function tuple:

Copied
config :sentry,
  dsn: "___PUBLIC_DSN___",
  enable_logs: true,
  before_send_log: {MyApp.Sentry, :before_send_log}

# In lib/my_app/sentry.ex
defmodule MyApp.Sentry do
  def before_send_log(%Sentry.LogEvent{} = log_event) do
    # Filter out logs from specific domains or modify attributes
    if String.contains?(log_event.body, "sensitive") do
      false
    else
      log_event
    end
  end
end

Logs behavior is configured under the :logs key in your Sentry configuration. These options control the auto-attached Sentry.LoggerHandler:

  • :level - The minimum log level to send to Sentry's Logs Protocol. Default: :info. Supported values: :debug, :info, :notice, :warning, :error, :critical, :alert, :emergency.

  • :excluded_domains - A list of logger domains to exclude from logs sent to Sentry. Default: [].

  • :metadata - Logger metadata keys to include as attributes in log events. Set to :all to include all metadata, or a list of specific keys like [:request_id, :user_id]. Default: [].

Copied
config :sentry,
  dsn: "___PUBLIC_DSN___",
  enable_logs: true,
  logs: [
    level: :info,
    excluded_domains: [:ecto],
    metadata: [:request_id, :user_id] # or :all
  ]

These options are set in your Sentry configuration (config :sentry):

  • :enable_logs - Set to true to enable the logs feature. When enabled, the SDK automatically attaches a Sentry.LoggerHandler and routes log events through the SDK's Telemetry Processor. Default is false.

  • :before_send_log - A callback function to filter or modify log events before they are sent.

Log events are buffered by the Telemetry Processor with a capacity of 1000 entries and flushed in batches of 100 or every 5 seconds, whichever comes first. You can customize these defaults through the Telemetry Processor options.

Copied
config :sentry,
  dsn: "___PUBLIC_DSN___",
  enable_logs: true,
  before_send_log: {MyApp.Sentry, :before_send_log}

The Elixir SDK automatically sets several default attributes on all log entries to provide context and improve debugging:

  • environment: The environment set in the SDK if defined. This is sent from the SDK as sentry.environment.
  • release: The release set in the SDK if defined. This is sent from the SDK as sentry.release.
  • sdk.name: The name of the SDK that sent the log. This is sent from the SDK as sentry.sdk.name.
  • sdk.version: The version of the SDK that sent the log. This is sent from the SDK as sentry.sdk.version.

If the log was parameterized, Sentry adds the message template and parameters as log attributes.

  • message.template: The parameterized template string. This is sent from the SDK as sentry.message.template.
  • message.parameter.X: The parameters to fill the template string. X can either be the number that represent the parameter's position in the template string (sentry.message.parameter.0, sentry.message.parameter.1, etc) or the parameter's name (sentry.message.parameter.item_id, sentry.message.parameter.user_id, etc). This is sent from the SDK as sentry.message.parameter.X.

  • server.address: The address of the server that sent the log. Equivalent to server_name that gets attached to Sentry errors.

If you're using OpenTelemetry with the opentelemetry_logger_metadata package, the following attributes are automatically included:

  • trace_id: The OpenTelemetry trace ID associated with the log event.
  • span_id: The OpenTelemetry span ID associated with the log event.

If no OpenTelemetry context is available, a random trace ID is generated to allow log correlation within Sentry.

Was this helpful?
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").