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.
mix deps.get sentry
mix deps.get sentry
Or add it to your mix.exs:
defp deps do
[
{:sentry, "~> 12.0"}
]
end
defp deps do
[
{:sentry, "~> 12.0"}
]
end
To enable logging, set enable_logs: true in your Sentry configuration:
# In config/config.exs or config/runtime.exs
config :sentry,
dsn: "___PUBLIC_DSN___",
enable_logs: true
# 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.
If you already have a Sentry.LoggerHandler registered (for example, for crash and error reporting), the SDK will not add a second one — your existing handler will also capture logs.
To configure the minimum log level and other options, use the :logs key:
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: [])
]
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: [])
]
Log events are automatically batched and delivered through the SDK's Telemetry Processor, which buffers log entries and sends them to Sentry efficiently. See the Telemetry Processor options for configuration details.
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.
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)
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:
# 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"]]
)
# 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:
config :sentry,
enable_logs: true,
logs: [
level: :info,
metadata: :all # or [:user_id, :request_id] for specific keys
]
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:
# Here `user_id` and `action` will be sent as extra attributes
Logger.info("User logged in", user_id: 123, action: "create")
# 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 tracing with OpenTelemetry, you can correlate logs with traces so that log events appear alongside spans in the Sentry Trace Explorer.
To enable this, add the opentelemetry_logger_metadata package to your dependencies:
mix.exsdefp deps do
[
{:opentelemetry_logger_metadata, "~> 0.2"},
# ... your other dependencies
]
end
defp deps do
[
{:opentelemetry_logger_metadata, "~> 0.2"},
# ... your other dependencies
]
end
Then call OpentelemetryLoggerMetadata.setup() in your application's start/2 callback:
lib/my_app/application.exdef start(_type, _args) do
OpentelemetryLoggerMetadata.setup()
# ... rest of your application setup
end
def start(_type, _args) do
OpentelemetryLoggerMetadata.setup()
# ... rest of your application setup
end
This package injects the active OpenTelemetry trace_id and span_id into Elixir's logger metadata. The Sentry SDK automatically picks up these IDs and includes them in every log event sent to Sentry, linking your logs to the trace they occurred within.
Without opentelemetry_logger_metadata, the SDK generates a random trace_id for each log event. Logs will still appear in Sentry, but they won't be connected to any trace.
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:
config :sentry,
enable_logs: true,
logs: [
level: :info,
metadata: [:request_id, :user_id]
]
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:
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:
config :sentry,
enable_logs: true,
logs: [
level: :info,
excluded_domains: [:ecto, :phoenix]
]
config :sentry,
enable_logs: true,
logs: [
level: :info,
excluded_domains: [:ecto, :phoenix]
]
Logs vs Error Reporting
The logs feature (configured under :logs) is separate from error reporting (configured via Sentry.LoggerHandler's :level option). Error reporting captures crash reports and exceptions, while logs captures structured log events. You can configure both independently.
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.
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
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:
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
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:allto include all metadata, or a list of specific keys like[:request_id, :user_id]. Default:[].
config :sentry,
dsn: "___PUBLIC_DSN___",
enable_logs: true,
logs: [
level: :info,
excluded_domains: [:ecto],
metadata: [:request_id, :user_id] # or :all
]
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 totrueto enable the logs feature. When enabled, the SDK automatically attaches aSentry.LoggerHandlerand routes log events through the SDK's Telemetry Processor. Default isfalse.: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.
config :sentry,
dsn: "___PUBLIC_DSN___",
enable_logs: true,
before_send_log: {MyApp.Sentry, :before_send_log}
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 assentry.environment.release: The release set in the SDK if defined. This is sent from the SDK assentry.release.sdk.name: The name of the SDK that sent the log. This is sent from the SDK assentry.sdk.name.sdk.version: The version of the SDK that sent the log. This is sent from the SDK assentry.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 assentry.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 assentry.message.parameter.X.
server.address: The address of the server that sent the log. Equivalent toserver_namethat 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 from the active trace context. Links the log to a specific trace in Sentry's Trace Explorer.span_id: The OpenTelemetry span ID from the active span context. Links the log to a specific span within the trace.
These attributes allow you to navigate from a log entry directly to the trace it occurred within, and vice versa.
If no OpenTelemetry context is available (for example, if opentelemetry_logger_metadata is not installed or the log occurs outside a traced operation), the SDK generates a random trace_id for each log event. In this case, span_id is not set, and logs are not connected to any trace in Sentry.
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").