对于基本的健康跟踪,Sentry
接受包含会话更新事件的 envelopes
。这些会话更新事件可用于通知 Sentry
有关 release
和 project
相关 project
健康状况的信息。
注意: 在本地使用 session
时,请确保使用必要的环境变量更新配置文件 ~/.sentry/sentry.config.py
:
SENTRY_EVENTSTREAM = 'sentry.eventstream.kafka.KafkaEventStream'
基本操作
Session
完全是client
驱动的。client
确定session
何时开始、结束或转变为不健康状态。
client
可以明确结束session
以记录时间或退出条件(崩溃等)。- 如果需要,
client
应在重新启动时明确结束session
,但session
不结束是可以接受的。
Session
通过保存整个session state
的会话更改事件
进行更新。Session
从发送的事件中更新。最近的事件保存整个session state
。发送到服务器的初始session event
被显式标记。Session
更新在实现时不得更改属性或数据损坏。请参阅下面关于属性不变性的部分。Session
只能更新5
天。如果一个会话在5
天内没有收到第二个事件,则永远是好的。Session
不一定要启动才崩溃。仅仅报告一次崩溃就足够了。
服务器模型
目前,Sentry
的 session system
已针对易于扩展性和操作成本进行了优化。这意味着该协议非常适合实现这一目标。其中一些优化显示在协议中,client
准确地遵循协议以避免在服务器上创建 bad data
非常重要。
服务器每小时都有预先物化(pre-materialized)
的 session
数据。当会话更新事件到来时,服务器将立即将数据具体化(materialize)
到正确的存储桶中。这意味着该协议仅限于“附加”。这也意味着 client
需要在其一侧存储会话的整个状态。
会话更新负载
一个 session update
是名为 session
的 envelope
中的一项。它包含一个大致如下所示的 JSON
负载:
{ "sid": "7c7b6585-f901-4351-bf8d-02711b721929", "did": "optional distinct user id", "init": true, "started": "2020-02-07T14:16:00Z", "duration": 60, "status": "exited", "attrs": { "release": "my-project-name@1.0.0", "environment": "environment name", "ip_address": "optional user ip address for filtering", "user_agent": "optional user agent for filtering" } }
请注意,这必须包含在 envelope
中。所以完整的事件看起来像这样:
{} {"type":"session"} {"sid":"..."}
存在以下字段:
sid
- String, optional. 会话 ID (唯一的并且由客户端生成的)。
如果初始会话状态为 exited
,则允许客户端跳过它。
did
- String, optional. Distinct ID. 应该是设备或用户 ID。
系统会在存储此 ID 之前自动对其进行哈希处理。
seq
- Number, optional. 一个逻辑时钟。默认为摄取期间的当前 UNIX 时间戳(以毫秒为单位)。
值 0
是保留的,因为 init
设置为 true
的会话将自动将 seq
强制为 0
。
timestamp
- String, optional. 会话更改事件发生时的时间戳。
必须是 ISO 日期时间字符串。如果未发送,服务器将采用当前的 UTC 时间戳。在数据模型中,这称为 received
。
started
- String, required. 会话开始时的时间戳。
必须是 ISO 日期时间字符串。
init
- Boolean, optional, 默认为
false
。
如果将其设置为 true
,则表示这是会话的第一个事件。这让服务器优化会话计数,因为不需要重复数据删除(客户端无论如何都是权威的)。在内部设置此标志时,处理时 seq
更改为0
。
duration
- Number, optional. 一个可选字段,可以在接收到事件时传输会话持续时间。这可以由客户端控制,例如,可以减去非活动时间(以浮点数表示的秒数)。
status
- String, optional, 默认是
ok
。会话的当前状态。
一个 session
只能有效地处于两种状态:ok
,这意味着会话处于活动状态
或终止状态
之一。当会话从 ok
移开时,它不能再被更新。
ok
: 会话当前正在进行中,但运行良好。这可以是会话的终止状态。exited
: 会话正常终止。crashed
: 会话因崩溃而终止。abnormal
: 会话遇到非崩溃相关的异常退出。
errors
- _Number, optional, 默认为
0
_。此会话正在进行时遇到的错误的运行计数器。
重要的是,当会话进入 crashed
时,此计数器也会增加。(例如:crash
本身也始终是一个 error
)。如果未设置或为 0
,摄取应强制 errors
为 1
。
attrs
- Object, required除了
release
之外的所有 key 都是可选的。具有以下属性的对象:
release
: Sentry Release ID (release
),建议格式为my-project-name@1.0.0
。environment
: Sentry 环境 (environment
)。ip_address
: 要考虑的主要 IP 地址。这通常是用户的 IP。此数据不会持久化,而是用于过滤。如果未设置,则自动填写 IP。user_agent
: 要考虑的user agent
。这通常是导致会话的用户的用户代理。此数据不会持久化,而是用于过滤。
Session Aggregates Payload(会话聚合有效负载)
特别是对于 request-mode(请求模式) 会话(见下文),通常每秒有数千个请求和会话。
假设这些 session
将是短时间的,并且不希望跟踪它们的持续时间, 那么在它们被发送到 Sentry
之前,可以在 SDK
端将这些 session
聚合在一起。
SDK
应聚合关闭的 session
,并按 started
时间、distinct_id
和 attrs
对它们进行分组。这些组将作为 sessions
envelope 项发送。它包含一个大致如下所示的 JSON
负载:
{ "aggregates": [ { "started": "2020-02-07T14:16:00Z", "exited": 123 }, { "started": "2020-02-07T14:16:00Z", "did": "optional distinct user id", "exited": 12, "errored": 3 } ], "attrs": { "release": "my-project-name@1.0.0", "environment": "development" } }
请注意,这必须包含在 envelope
中。所以完整的 envelope
看起来像这样:
{} {"type": "sessions"} {"aggregates": [...], "attrs": {...}}
aggregates
- Array, required. 按
started
时间戳和distinct id (did)
分组的聚合数组。
started
: Required. 组的时间戳,四舍五入到分钟。必须是 ISO 日期时间字符串。did
: Optional. 组的distinct user id
。exited
: Optional. 状态为"exited"
且没有任何错误的session
数。abnormal
: Optional. 状态为"abnormal"
的session
数。crashed
: Optional. 状态为"crashed"
的session
数。errored
: Optional. 状态为"exited"
且errors
计数不为零的session
数。
attrs
- Object, required. 见上文。
崩溃与会话
会话(Session)
和错误(error)
事件是 Sentry
中两个不同的系统。 Session
更新可以在不发送错误事件的情况下完成,同样,可以在没有 session
更新的情况下发送 error
。
这使 client
可以完全控制应如何执行 session
更新。激励因素是服务器可以在某些情况下自由拒绝 error
事件,在这种情况下记录 session
信息仍然很有趣。例如,如果项目对 error
事件应用了 rate limit
,则它们的 session
数据仍然可以绕过此 rate limit
路由到项目。
但是,强烈建议在与 crash
事件相同的 envelope
中发送 session
更新,以防 session
转换到 crashed
状态。如果网络不可靠,这将确保事件同时到达系统。
重要客户端行为
这些是 client
必须遵守的重要规则:
属性不可变性
当前不允许 session
更改后续更新中的任何属性,包括 did
、started
或其他属性。唯一允许更改的属性是 session
状态、持续时间或错误计数。如果一开始不知道 user
,则应该延迟 session
开始,或者一旦知道 user
就应该重新启动 session
。
会话计数/初始化
发送到系统的初始 session
更新必须将 init
设置为 true
。这是必要的,因为服务器当前不会将总 session 计数
作为优化进行重复数据删除。如果初始的 init: true
flag 丢失,则 Sentry
可能无法正确摄取 session
。
终止会话状态
Session
可以存在两种状态:进行中(progress)
或终止(terminated)
。终止的 session
不得接收进一步的更新。退出(exited)
、崩溃(crashed)
和异常(abnormal)
都是终止状态。当 session
达到此状态时,client
不得再报告任何 session
更新或启动新 session
。
鼓励 SDK
区分结束 session
的不同方式:
exited
: 这意味着session
干净地结束了。从成功报告的角度来看,这与保持ok
的session
没有任何不同。但是,只有以exited
结尾的session
才会被考虑用于session
持续时间。即使发生error
,session
也可以进入exited
状态。crashed
: 在以下情况下,session
应报告为crashed
:
- 发生
未处理的错误(unhandled error)
并且session
自然结束(例如:HTTP
请求结束) - 应用程序完全崩溃(崩溃到桌面,终止)
- 用户
反馈(feedback)
对话框显示给用户。在此之后,SDK
必须启动一个新session
,就像它完全崩溃一样。
abnormal
: 如果可以的话,鼓励SDK
始终将session
转换为exited
或crashed
。对于能够始终结束session
的SDK
,如果无法检测到应用程序正确关闭, 则应以abnormal
结束session
。异常session
示例:
异常的session
结束通常会在应用程序重新启动时被记录下来。
- 计算机被关闭/断电
- 用户通过
kill -9
或任务管理器强制关闭应用程序
崩溃、异常与错误
Session
应该在遇到未处理的错误(例如应用程序完全崩溃)时转换为 crashed
。对于无法完全崩溃的应用程序(例如网站),如果用户遇到错误对话框,则转换到 crashed
状态是可以接受的。对于我们为每个传入请求创建 session
的 server
环境,crashed
基本上就像状态代码 500
内部服务器错误。因此,如果在请求期间发生未处理的错误(unhandled error)
,会话应该 crashed
。
Abnormal
是其命运未知的 session
。例如,对于桌面应用程序,如果 session
被存储但未观察到应用程序退出但也没有崩溃, 则将 session
转换为 abnormal
是有意义的。在这些情况下,用户通过任务管理器强制关闭应用程序、机器断电或其他情况。可以通过将 session
持久保存到磁盘来存储 session
。这个保存的文件可以在应用程序重启时检测到,以关闭 abnormal
的会话。
错误的 session
由大于零的 errors
计数器确定。 client
需要对被视为 error
的事件进行计数,并将计数与 session
更新一起发送。正常且错误计数大于零的 session
被视为错误 session
。所有崩溃和异常 session
也始终被视为错误,但会从最终错误 session
计数中减去。
退出
Session
可以转换为 exited
,这与 ok
状态完全相同, 但有一个区别:转换为 exited
的 session
的 session
持续时间是平均的。这让 Sentry
向您显示非崩溃 session
的持续时间。
警报
当 issue
影响到指定百分比的会话时触发警报。创建新的 issue alert 并选择 "When"
条件 An issue affects more than {X} percent of sessions(问题影响超过 {X}% 的会话)
。在 Issue Alert Configuration 文档中查看更多问题警报选项。
- https://docs.sentry.io/product/alerts/alert-types/#issue-alerts
- https://docs.sentry.io/product/alerts/create-alerts/issue-alert-config/
SDK 注意事项
一般来说,SDK
可以使用两种独立的健康报告模式。一个是非常短暂的 session
,另一个是用户参与的 session
。
短时会话(server-mode / request-mode)
这些 session
大致对应于服务器设置中的 HTTP
请求或 RPC
调用。
- 海量请求, 通常每个请求一个会话
Session
数通常高于Sentry
事件数Session
附加到单个hub/concurrency unit
- 计时信息通常是无用的,因为
session
时间以毫秒为单位
用户参与的会话(user-mode / application-mode)
这些 session
更对应于实际的用户 session
或应用程序运行。这就是您在 Web 浏览器、移动世界、命令行应用程序或类似应用程序中会看到的内容。
- 通常只是从应用程序开始到退出的单个
session
- 如果适用,一旦应用程序置于后台超过
30
秒(移动SDK
),session
就可以结束 session
次数通常少于Sentry
事件session
跨越多个hub/thread
session
持续时间通常以分钟为单位,计时信息很有用
从 API 的角度来看,这两种情况看起来很相似,但对于 SDK 的建议不同。
选择会话模式
虽然理论上可以在单个应用程序中使用两种会话模式,但建议 SDK 默认使用最适合语言生态系统主要用例的单一模式。这类似于某些 SDK 支持的全局 Hub 模式,并且可以以相同的方式使用。
当 SDK
配置为使用 user-mode 会话或全局 Hub
模式时,应在应用程序启动时启动单个会话,并应在应用程序的运行时持续存在。根据 SDK
内部结构,此单个 session
可以在所有应用程序线程和线程本地 Hub
之间共享。
使用 server-mode 会话时,不会启动应用程序范围的 session
, 并且由集成或用户在收到请求时启动 session
并在返回响应时结束 session
。
统一 API 的含义
SDK 应该遵循的统一 API 定义了 Hub
、Scope
和 Client
的概念。
从概念上讲,session
是 Hub
的关注点,与 scope
不同,session
不应嵌套。当任何一种事件发生时,应该只有一个明确的 session
来跟踪错误计数。
在考虑通过 SDK
的事件流时,从静态 capture_event
函数,通过线程本地 Hub
,进入 Client::capture_event(event, scope)
方法;根据 SDK
的内部实现细节,将 session
附加到 Scope
可能是有意义的, 这将使 Client
可以将 event
和 session
更新捆绑到单个 envelope
中以发送到 Sentry
。
会话更新以及何时向上游发送更新
对于所有 SDK
,只要在调用 apply_to_scope
的类似位置捕获数据以增加 error
计数, 或根据 distinct ID / user ID
更新 session
,将自动更新当前 session
。
SDK
通常应旨在减少向上游发送的 envelope
数量。
跟踪大量会话的 server-mode SDK 应考虑使用定期 session
刷新器(每 60
秒), 将会话预聚合到单个 session_aggregates
envelope 项中。
User-Mode SDK 可能会选择在同一 envelope
中发送 session
更新以及捕获的事件。关闭 session
的最终 session
更新可以类似于 Server-Modesession
进行批处理。
在任何一种情况下,必须为 session
的第一次传输正确设置 init
标志, 并且 session
元数据(例如 distinct ID
)在初始传输后必须是不可变的。
会话的预聚合
如果 SDK
配置为使用 server-modesession
,则应在将 session
计数发送到 Sentry
之前对其进行分组和预聚合。每当 session
关闭(转换到 terminal
状态),并且之前没有向上游发送(其 init
标志为 true
)时,它就有资格进行聚合,其执行方式如下:
Session
的started
时间戳应四舍五入到分钟。- 然后必须将
Session
聚合到由该舍入时间戳标识的存储bucket
中,以及会话的distinct id
(did
)。 - 在适当的
bucket
中,根据session
状态增加session
计数。与单个session
更新相反,"errored"
状态用于标记具有"exited"
状态和非零errors
计数的会话。
公开 API
公开的最基本的 API
位于 hub
级别,可让您启动和停止 session
记录:
API:
Hub.start_session()
在当前 scope 上存储一个 session 并开始跟踪它。这通常会将一个全新的 session 附加到 scope,并隐式地结束任何已经存在的 session。
Hub.end_session()
结束 session,设置适当的
status
和duration
,并将其加入队列以发送到Sentry
。
Hub.start_auto_session_tracking()
/ Hub.stop_auto_session_tracking()
停止并重新激活自动 session 跟踪。
初始化选项:
auto_session_tracking
这通过集成
启用/禁用
自动session
跟踪。
SDK 实现指南
在开始在 SDK 中实现此功能之前,请与团队联系。
我们通过从 SDK
发送 session
有效负载来跟踪 Sentry
中每个项目 release
的健康状况。 Session
有效负载提供诸如 session
持续时间以及是否存在错误/崩溃
等数据。
SDK 以两种模式之一跟踪 session
:
- 单个 Session
- Session 聚合
单个 session
是一般情况,非常适合通常只涉及单个用户的(相对短暂的)应用程序。例子:
- 命令行实用程序,如
craft
;craft
子命令的每次执行都会向Sentry
报告一个session
- 用户与
mobile app
交互 - 用户使用他们最喜欢的浏览器加载网站
当发送单个 session
不受欢迎或不切实际时,将使用 session
聚合。为了限制资源使用(即内存
和网络
),SDK
会跟踪有关最近发生的一批会话的摘要信息, 实际上不必处理代表构成聚合的各个 session
的 session
对象。此模式适用于运行任意长时间并为潜在的多个用户处理更大吞吐量的应用程序,例如 Web Server
、后台 Job Worker
等。请注意,对于这些类型的应用程序,session
的更好定义与执行匹配单个 HTTP 请求或任务,而不是整个应用程序进程的单个执行。
在任何一种情况下,SDK
都应默认创建和报告 session
,根据应用程序类型选择单独报告或作为聚合报告。
如果 SDK
可以检测到 session
聚合更好地为应用程序提供服务,则它不得报告应用程序范围的 session
。应用程序范围的 session
可能仍会在 SDK
初始化期间创建,但必须中止并且永远不会发送到 Sentry
。例如,在 Node.js SDK
中,如果应用程序使用提供的 requestHandler
集成,我们可以检测到它可能是一个 web server
。
单个会话功能
配置
全局/静态
API
默认开启;
如果用户不想跟踪 session
,他们应该能够禁用 session
。
报告 session
和确定 Sentry
中项目的 Release Health
的先决条件,例如 release
应由 SDK
自动检测,例如通过查找 env
变量。
(也许,需要讨论)如果我的先决条件不能被检测到(例如,没有好的方法来确定 release
版本), 那么我们设置一些默认值,以便我们总是可以默认报告 session
(取决于讨论,这可能不会是 SDK
代码的更改,但在 Relay
中,基本上删除了 session
有效负载中的硬要求)。
会话的生命周期
默认情况下,会话应该只为由 Sentry.init
初始化的全局 hub/client
启用,并默认为任何其他手动创建的 client
禁用。 Session
在 SDK
初始化时开始(理想情况下,当默认 client
绑定到全局 hub
时)并在以下情况之一发生时结束:显式调用 Hub.endSession()
方法;或程序无错误终止;或程序以未处理的异常终止;或程序以未处理的 promise rejection
而终止。
必须注意永远不要尝试为已经结束的 session
向 Sentry
发送新的 session
负载。例如,如果用户使用 Hub.endSession()
手动结束 session
,则程序终止时不应有任何新的 session
更新。
会话属性和可变性
向 Sentry 发送会话
Session
最初在一定的(最初是硬编码的,配置越少越好)延迟(大约 1
到 30
秒 TBD
)后发送, 然后在程序终止时更新持续时间、最终状态和错误计数。请注意,作为一种优化,short lived
程序不会向 Relay
发送 2
个 session
请求, 而只会向 Relay
发送最后一个带有状态和持续时间的请求。
会话聚合功能
配置
默认情况下应启用 session
,session
在 web server
收到请求后立即启动,并在响应完全发回后立即结束。
会话的生命周期
Session
从不被跟踪或单独发送,相反,它们被聚合,聚合每 30
秒发送一次,最后一次当 web server
终止。作为对上述点的实现提示,当 "Client"
关闭或刷新时,相关联的 "Session Flusher"
也应被刷新并在传输被刷新/关闭
之前提交当前聚合。确保这对于 Serverless
来说是合理的 — 我们不会使用 "request mode"
和 SessionFlusher
,因为我们不能在 request-response
流之外进行任何工作。提供一种与现有 Node
框架(Express
、Next.js
、Koa
)集成的简单方法。