View Source Sentry.Context (Sentry v10.8.0)
Provides functionality to store user, tags, extra, and breadcrumbs context when an event is reported.
The contexts will be fetched and merged into the event when it is sent.
Sentry.Context
uses Elixir Logger
metadata to store the context itself.
This imposes some limitations. The metadata will only exist within
the current process, and the context will disappear when the process
dies. For example, if you add context inside your controller and an
error happens in a spawned Task
, that context will not be included.
A common use case is to set context when handling requests within Plug or Phoenix applications, as each request is its own process, and so any stored context is included should an error be reported within that request process. For example:
# post_controller.ex
def index(conn, _params) do
Sentry.Context.set_user_context(%{id: conn.assigns.user_id})
posts = Blog.list_posts()
render(conn, "index.html", posts: posts)
end
Merging
The
set_*_context/1
functions merge with the existing context rather than entirely overwriting it.
Sentry Documentation
Sentry itself documents the meaning of the various contexts:
Summary
Functions
Adds an attachment to the current context.
Adds a new breadcrumb to the :breadcrumb
context, specific to the current
process.
Clears all existing context for the current process.
Clears all attachments from the current context.
Returns the keys used to store context in the current process' logger metadata.
Retrieves all currently-set context on the current process.
Merges new fields into the :extra
context, specific to the current process.
Merges new fields into the :request
context, specific to the current
process.
Merges new fields into the :tags
context, specific to the current process.
Merges new fields into the :user
context, specific to the current process.
Types
@type breadcrumb() :: %{ optional(:type) => :default | :debug | :error | :navigation | String.t(), optional(:category) => String.t(), optional(:message) => String.t(), optional(:data) => map(), optional(:level) => :fatal | :error | :warning | :info | :debug, optional(:timestamp) => String.t() | integer(), optional(atom()) => term() }
Breadcrumb info.
See add_breadcrumb/1
.
Example
%{
type: "default",
category: "ui.click",
data: nil,
level: "info",
message: "User clicked on the main button",
timestamp: 1596814007.035
}
A map of extra data.
See set_extra_context/1
.
@type request_context() :: %{ optional(:method) => String.t() | nil, optional(:url) => String.t() | nil, optional(:query_string) => String.t() | map() | [{String.t(), String.t()}] | nil, optional(:data) => term(), optional(:cookies) => String.t() | map() | [{String.t(), String.t()}] | nil, optional(:headers) => map() | nil, optional(:env) => map() | nil }
Request context.
See set_request_context/1
. This map gets eventually converted
into a Sentry.Interfaces.Request
struct.
A map of tags.
See set_tags_context/1
.
@type user_context() :: %{ optional(:id) => term(), optional(:username) => String.t(), optional(:email) => String.t(), optional(:ip_address) => term(), optional(:segment) => term(), optional(:geo) => %{ optional(:city) => String.t(), optional(:country_code) => String.t(), optional(:region) => String.t() }, optional(atom()) => term() }
User context.
See set_user_context/1
.
You can use "{{auto}}"
as the value of :ip_address
to let Sentry infer the
IP address (see the documentation for automatic IP
addresses).
Other than the keys specified in the typespec below, all other keys are stored as extra information but not specifically processed by Sentry.
Example
%{
user: %{
id: "unique_id",
username: "my_user",
email: "foo@example.com",
ip_address: "127.0.0.1",
# Extra key
subscription: "basic"
}
}
Functions
@spec add_attachment(Sentry.Attachment.t()) :: :ok
Adds an attachment to the current context.
Attachments stored in the context will be sent alongside each event that is reported within that context (that is, within the process that the context was set in).
Currently, there is no limit to how many attachments you can add to the context
through this function, even though there might be limits on the Sentry server side.
To clear attachments, use clear_attachments/0
.
Examples
iex> Sentry.Context.add_attachment(%Sentry.Attachment{filename: "foo.txt", data: "foo"})
:ok
iex> Sentry.Context.add_attachment(%Sentry.Attachment{filename: "bar.txt", data: "bar"})
:ok
iex> Sentry.Context.get_all()
%{
attachments: [
%Sentry.Attachment{filename: "bar.txt", data: "bar"},
%Sentry.Attachment{filename: "foo.txt", data: "foo"}
],
breadcrumbs: [],
extra: %{},
request: %{},
tags: %{},
user: %{}
}
@spec add_breadcrumb(keyword() | breadcrumb()) :: :ok
Adds a new breadcrumb to the :breadcrumb
context, specific to the current
process.
Breadcrumbs are used to record a series of events that led to a specific instance of an error. Breadcrumbs can contain arbitrary key data to assist in understanding what happened before an error occurred.
See the Sentry documentation for more information.
If breadcrumb_info
is a keyword list, it should be convertible to a map of type
breadcrumb/0
.
If not present, the :timestamp
key is filled in automatically with the current
Unix timestamp (in seconds).
Example
iex> Sentry.Context.add_breadcrumb(message: "first_event")
:ok
iex> Sentry.Context.add_breadcrumb(%{message: "second_event", type: "auth"})
%{breadcrumbs: [%{:message => "first_event", "timestamp" => 1562007480}]}
iex> Sentry.Context.add_breadcrumb(%{message: "response"})
%{
breadcrumbs: [
%{:message => "second_event", :type => "auth", "timestamp" => 1562007505},
%{:message => "first_event", "timestamp" => 1562007480}
]
}
iex> Sentry.Context.get_all()
%{
attachments: [],
breadcrumbs: [
%{:message => "first_event", "timestamp" => 1562007480},
%{:message => "second_event", :type => "auth", "timestamp" => 1562007505},
%{:message => "response", "timestamp" => 1562007517}
],
extra: %{},
request: %{},
tags: %{},
user: %{}
}
@spec clear_all() :: :ok
Clears all existing context for the current process.
Example
iex> Sentry.Context.set_tags_context(%{id: 123})
:ok
iex> Sentry.Context.clear_all()
:ok
iex> Sentry.Context.get_all()
%{breadcrumbs: [], extra: %{}, request: %{}, tags: %{}, user: %{}, attachments: []}
@spec clear_attachments() :: :ok
Clears all attachments from the current context.
See add_attachment/1
.
Examples
iex> Sentry.Context.add_attachment(%Sentry.Attachment{filename: "foo.txt", data: "foo"})
:ok
iex> Sentry.Context.clear_attachments()
:ok
iex> Sentry.Context.get_all().attachments
[]
@spec context_keys() :: [atom(), ...]
Returns the keys used to store context in the current process' logger metadata.
Example
iex> Sentry.Context.context_keys()
[:breadcrumbs, :tags, :user, :extra, :request, :attachments]
@spec get_all() :: %{ user: user_context(), request: request_context(), tags: tags(), extra: extra(), breadcrumbs: list(), attachments: [Sentry.Attachment.t()] }
Retrieves all currently-set context on the current process.
Example
iex> Sentry.Context.set_user_context(%{id: 123})
iex> Sentry.Context.set_tags_context(%{message_id: 456})
iex> Sentry.Context.get_all()
%{
user: %{id: 123},
tags: %{message_id: 456},
extra: %{},
request: %{},
breadcrumbs: [],
attachments: []
}
@spec set_extra_context(extra()) :: :ok
Merges new fields into the :extra
context, specific to the current process.
This is used to set fields which should display when looking at a specific instance of an error.
Example
iex> Sentry.Context.set_extra_context(%{id: 123})
:ok
iex> Sentry.Context.set_extra_context(%{detail: "bad_error"})
:ok
iex> Sentry.Context.set_extra_context(%{message: "Oh no"})
:ok
iex> Sentry.Context.get_all()
%{
user: %{},
tags: %{},
extra: %{detail: "bad_error", id: 123, message: "Oh no"},
request: %{},
breadcrumbs: [],
attachments: []
}
@spec set_request_context(request_context()) :: :ok
Merges new fields into the :request
context, specific to the current
process.
This is used to set metadata that identifies the request associated with a specific instance of an error.
The request context is documented in the Sentry documentation.
Invalid Keys
While this function accepts any map with atom keys, the only keys that are valid are those in
request_context/0
. We don't validate keys because of performance concerns, so it's up to you to ensure that you're passing valid keys.
Example
iex> Sentry.Context.set_request_context(%{url: "example.com"})
:ok
iex> headers = %{"accept" => "application/json"}
iex> Sentry.Context.set_request_context(%{headers: headers, method: "GET"})
:ok
iex> Sentry.Context.get_all()
%{
attachments: [],
breadcrumbs: [],
extra: %{},
request: %{method: "GET", headers: %{"accept" => "application/json"}, url: "example.com"},
tags: %{},
user: %{}
}
@spec set_tags_context(tags()) :: :ok
Merges new fields into the :tags
context, specific to the current process.
This is used to set fields which should display when looking at a specific instance of an error. These fields can also be used to search and filter on.
Example
iex> Sentry.Context.set_tags_context(%{id: 123})
:ok
iex> Sentry.Context.set_tags_context(%{other_id: 456})
:ok
iex> Sentry.Context.get_all()
%{
attachments: [],
breadcrumbs: [],
extra: %{},
request: %{},
tags: %{id: 123, other_id: 456},
user: %{}
}
@spec set_user_context(Sentry.Interfaces.user()) :: :ok
Merges new fields into the :user
context, specific to the current process.
This is used to set certain fields which identify the actor who experienced a specific instance of an error.
The user context is documented in the Sentry documentation.
Additional Keys
While at least one of the keys described in
Sentry.Interfaces.user/0
is recommended, you can also add any arbitrary key to the user context.
Example
iex> Sentry.Context.set_user_context(%{id: 123})
:ok
iex> Sentry.Context.set_user_context(%{username: "george"})
:ok
iex> Sentry.Context.get_all()
%{
user: %{id: 123, username: "george"},
tags: %{},
extra: %{},
request: %{},
breadcrumbs: [],
attachments: []
}