diff --git a/README.md b/README.md index abde5298..976ce0ca 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,30 @@ default value is not in the list of `included_environments`. Sentry uses the [hackney HTTP client](https://github.com/benoitc/hackney) for HTTP requests. Sentry starts its own hackney pool named `:sentry_pool` with a default connection pool of 50, and a connection timeout of 5000 milliseconds. The pool can be configured with the `hackney_pool_max_connections` and `hackney_pool_timeout` configuration keys. If you need to set other [hackney configurations](https://github.com/benoitc/hackney/blob/master/doc/hackney.md#request5) for things like a proxy, using your own pool or response timeouts, the `hackney_opts` configuration is passed directly to hackney for each request. +### Context and Breadcrumbs + +Sentry has multiple options for including contextual information. They are organized into "Tags", "User", and "Extra", and Sentry's documentation on them is [here](https://docs.sentry.io/learn/context/). Breadcrumbs are a similar concept and Sentry's documentation covers them [here](https://docs.sentry.io/learn/breadcrumbs/). + +In Elixir this can be complicated due to processes being isolated from one another. Tags context can be set globally through configuration, and all contexts can be set within a process, and on individual events. If an event is sent within a process that has some context configured it will include that context in the event. Examples of each are below, and for more information see the documentation of [Sentry.Context](https://hexdocs.pm/sentry/Sentry.html#module-filtering-exceptions). + +```elixir +# Global Tags context via configuration: + +config :sentry, + tags: %{my_app_version: "14.30.10"} + # ... + +# Process-based Context +Sentry.Context.set_extra_context(%{day_of_week: "Friday"}) +Sentry.Context.set_user_context(%{id: 24, username: "user_username", has_subscription: true}) +Sentry.Context.set_tags_context(%{locale: "en-us"}) +Sentry.Context.add_breadcrumb(%{category: "web.request"}) + +# Event-based Context +Sentry.capture_exception(exception, [tags: %{locale: "en-us", }, user: %{id: 34}, + extra: %{day_of_week: "Friday"}, breadcrumbs: [%{timestamp: 1461185753845, category: "web.request"}]] +``` + ### Fingerprinting By default, Sentry aggregates reported events according to the attributes of the event, but users may need to override this functionality via [fingerprinting](https://docs.sentry.io/learn/rollups/#customize-grouping-with-fingerprints). diff --git a/docs/index.rst b/docs/index.rst index 0c57ffb8..85285a2b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -88,27 +88,6 @@ If using an environment with Plug or Phoenix add the following to your router: use Sentry.Plug -Adding Context --------------- - -Sentry allows a user to provide context to all error reports, Elixir being multi-process makes this a special -case. When setting a context we store that context in the process dictionary, which means if you spin up a -new process and it fails you might lose your context. That said using the context is simple: - -.. code-block:: elixir - - # sets the logged in user - Sentry.Context.set_user_context(%{email: "foo@example.com"}) - - # sets the tag of interesting - Sentry.Context.set_tags_context(%{interesting: "yes"}) - - # sends any additional context - Sentry.Context.set_extra_context(%{my: "context"}) - - # adds an breadcrumb to the request to help debug - Sentry.Context.add_breadcrumb(%{my: "crumb"}) - Filtering Events ---------------- @@ -137,6 +116,36 @@ allows other exceptions to be sent. included_environments: ~w(production staging), environment_name: System.get_env("RELEASE_LEVEL") || "development" +Context and Breadcrumbs +---------------- + +Sentry has multiple options for including contextual information. They are organized into +"Tags", "User", and "Extra", and Sentry's documentation on them is `here `_. +Breadcrumbs are a similar concept and Sentry's documentation covers them `here `_. + +In Elixir this can be complicated due to processes being isolated from one another. Tags +context can be set globally through configuration, and all contexts can be set within a +process, and on individual events. If an event is sent within a process that has some context +configured it will include that context in the event. Examples of each are below, +and for more information see the documentation of `Sentry.Context `_. + +.. code-block:: elixir + # Global Tags context via configuration: + + config :sentry, + tags: %{my_app_version: "14.30.10"} + # ... + + # Process-based Context + Sentry.Context.set_extra_context(%{day_of_week: "Friday"}) + Sentry.Context.set_user_context(%{id: 24, username: "user_username", has_subscription: true}) + Sentry.Context.set_tags_context(%{locale: "en-us"}) + Sentry.Context.add_breadcrumb(%{category: "web.request"}) + + # Event-based Context + Sentry.capture_exception(exception, [tags: %{locale: "en-us", }, user: %{id: 34}, + extra: %{day_of_week: "Friday"}, breadcrumbs: [%{timestamp: 1461185753845, category: "web.request"}]] + Fingerprinting ---------------- By default, Sentry aggregates reported events according to the attributes of the event, diff --git a/lib/sentry/context.ex b/lib/sentry/context.ex index d0d2d426..7b1c9a19 100644 --- a/lib/sentry/context.ex +++ b/lib/sentry/context.ex @@ -1,15 +1,25 @@ defmodule Sentry.Context do @moduledoc """ - Provides a method to store user, tags, and extra context when an - event is reported. The contexts will be fetched and merged into - the event. + 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 the Process Dictionary to store this state. - This imposes some limitations. The state will only exist within + When calling Sentry.Context, the Process Dictionary is used to store this state. + This imposes some limitations. The state will only exist within the current process, and the context will die with the process. - For example, if you add context inside your controller and an - error happens in a Task the context won't send. + For example, if you add context inside your controller and an + error happens in a Task, that context will not be included. + + A common use-case is to set context within Plug or Phoenix applications, as each + request is its own process, and so any stored context will be included should an + error be reported within that request process. 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 """ @process_dictionary_key :sentry_context @user_key :user