新的 Sentry SDK
应遵循 Unified API
,使用一致的术语来指代概念。本文档说明了 Unified API
是什么以及为什么它存在。
Sentry
有各种各样的 SDK
,这些 SDK
是由不同的开发人员根据不同的想法在过去几年里开发出来的。这导致了不同 SDK
的特性设置不同,使用不同的概念和术语,这导致了通常不清楚如何在不同的平台上实现相同的东西。
此外,这些 SDK
完全以通过 explicit clients
进行错误报告为中心,这意味着通常无法进行某些集成(例如面包屑 breadcrumbs
)。
SDK API
的语言/措辞统一,以辅助支持和文档编制,并使用户更轻松地在不同环境中使用 Sentry
。SDK
时,我们可以添加一些新的功能,而不是单纯的事件报告(transactions
,APM
等)。client
实例的 SDK
,我们既可以通过依赖项注入等在运行时环境中自然工作,也可以使用隐式上下文分派给已经存在的 clients
和 scopes
,以挂接到大多数环境中。这很重要,因为它允许事件将流程中其他集成的数据包括在内。API
需求在大多数语言中都是有意义的,并且一定不能依赖于超级特殊的构造。为了使它更自然,我们应该考虑语言细节,并明确地支持它们作为替代方法(disposables
, stack guards
等)。“facade”
包,它通过接口(interfaces
)或代理(proxies
)重新导出 SDK
功能的子集。该包不直接依赖于 SDK
,相反,如果没有安装 SDK
,它应该使每个操作都成为 noop
。这样一个包的目的是允许 random
库记录面包屑和设置上下文数据,同时不依赖 SDK
。global thread local
或类似的 hub
。Hubs
可以手动创建。scope
包含了应该与 Sentry
事件一起隐式发送的数据。它可以保存上下文数据、额外参数、级别覆盖、指纹等。client
是只配置一次的对象,可以绑定到 hub
。然后,用户可以自动发现 client
并分派对它的调用。用户通常不需要直接与 client
打交道。它们要么通过 hub
实现,要么通过 static convenience functions
实现。client
主要负责构建 Sentry
事件并将其发送到 transport
。client
。这可以是 release
和 environment
,也可以是要配置的 integrations
,in-app works
等。Contexts
为 Sentry
提供额外的数据。有特殊的上下文( user
和类似的)和通用的上下文(runtime,os,device),等等。检查有效键的 Contexts
。注意:在旧的 SDK
中,您可能会遇到一个与上下文无关的概念,这个概念现在已被作用域弃用。Tags
可以是任意 string
→ 可以搜索事件的 string pairs
。 Contexts
被转换为 tags
。client users
附加的真正任意数据。这是一个已弃用的特性,但在可预见的未来将继续得到支持。鼓励用户使用上下文代替。transport
是对事件发送进行抽象的客户端的内部构造。通常,transport
在单独的线程中运行,并获取通过队列发送的事件。transport
负责发送(sending
)、重试(retrying
)和处理速率限制(handling rate limits
)。如果需要,transport
还可能在重启过程中持久化未发送的事件。frameworks
)或环境(environments
)提供中间件(middlewares
)、绑定(bindings
)或钩子(hooks
)的代码,以及插入这些绑定并激活它们的代码。集成的使用不遵循公共接口。Callbacks
)。他们可以修改并返回事件,或者可以为 null
。返回 null
将丢弃该事件,并且不会进一步处理。有关更多信息,请参见事件管道(Event Pipeline
)。SDK
功能依赖于已配置的 active client
。当有 transport
时,Sentry 认为 client
是 active
的。否则,客户端是 inactive
的,SDK
被认为是 “disabled”
。在这种情况下,某些回调函数,例如 configure_scope
或事件处理器(event processors
),可能不会被调用。因此,面包屑(breadcrumbs
)不会被记录下来。静态 API
函数是最常见的面向用户的 API
。用户只需导入这些功能,即可开始向 Sentry
发出事件或配置作用域。这些快捷方式功能应在包的顶级名称空间中导出。他们在后台使用 hubs
和 scopes
(有关更多信息,请参见并发性 Concurrency
)(如果在该平台上可用)。请注意,下面列出的所有函数大部分都是 Hub::get_current().function
的别名。
init(options)
:这是每个 SDK
的入口点。通常,这会创建(creates
)/重新初始化(reinitializes
)传播到所有新线程(new threads
)/执行上下文(execution contexts
)的global hub
,或者为每个线程(per thread
)/执行上下文(execution context
)创建一个 hub
。
接受 options
(dsn
等),配置 client
并将其绑定到当前 hub
或对其进行初始化。应返回一个 stand-in
,可用于 drain events
(一次性)。
这可能会返回一个 handle
或 guard
来处理。如何实现这一点完全取决于 SDK
。这甚至可能是一个 client
,如果这对 SDK
有意义的话。在 Rust
中,它是一个 ClientInitGuard
,在 JavaScript
中,它可以是一个带有可等待的 close
方法的 helper
对象。
您应该能够多次调用此方法,而第二次调用它既可以拆除先前的 client
,也可以减少先前 client
的引用计数,等等。
多次调用只能用于测试。如果您在应用程序启动以外的任何时间调用 init
,将会是 undefined
。
用户必须调用一次 init
,但允许使用禁用的 DSN
进行调用。例如可能没有参数传递等。
此外,它还设置了所有默认的集成。
capture_event(event)
:接受一个已经组合好的事件,并将其调度到当前活动的中心。事件对象可以是普通字典或类型化的对象,无论在SDK中更有意义。它应尽可能遵循本机协议,而忽略平台特定的重命名(案例样式等)。capture_exception(error)
:报告 error
或 exception
对象。根据平台的不同,可能有不同的参数。最明显的版本只接受一个 error
对象,但在不传递 error
且使用当前 exception
的情况下也可能发生变化。capture_message(message, level)
:报告 message
。级别可以是可选的语言默认参数,在这种情况下,它应该默认为 info
。add_breadcrumb(crumb)
:向 scope
添加新的面包屑。如果面包屑的总数超过 max_breadcrumbs
设置,则 SDK
应删除最旧的面包屑。这与 Hub API
的工作原理类似。如果禁用了 SDK
,它应该忽略 breadcrumb
。configure_scope(callback)
:可以重新配置 scope
对象调用的回调。这用于为相同范围内的未来事件附加上下文数据。last_event_id()
:应该返回当前作用域发出的最后一个事件 ID
。例如,这用于实现用户反馈对话框(feedback
)。所有 SDK
都应具有并发安全上下文存储(concurrency safe context storage
)的概念。这意味着什么取决于语言。基本思想是,SDK
的用户可以调用一种方法来为即将记录的所有事件安全地提供其他上下文信息。
在大多数语言中,这是作为 thread local stack
实现的,但在某些语言中(比如 JavaScript
),它可能是全局的,因为假设这在环境中是有意义的。
以下是一些常见的并发模式:
thread
都有自己的 “hub”
,该 hub
在内部管理一系列作用域scopes
。如果遵循该模式,则一个 thread
(调用 init()
的线程)将成为 “main” hub
,该 hub
将用作新生成的线程的基础,该线程将获得基于主 hub
的 hub
(但又是独立的)。.NET ambient data
是可用的,在这种情况下 Hub
可以内部管理作用域scopes
。concurrency
本身并不存在。在这种情况下,hub
可能完全不存在,或者只是一个没有并发管理concurrency management
的单例。在正常情况下,hub 由一堆 clients
和 scopes
组成。
SDK
维护两个变量:main hub
(一个全局变量)和 current hub
(当前线程thead
或执行上下文execution context
的本地变量,有时也称为异步本地async local
或上下文本地context local
变量)
Hub::new(client, scope)
:使用给定的 client
和 scope
创建一个新的 hub
。client
可以在 hubs
之间重用。scope
应归 hub
所有(如有必要,请进行 clone
)Hub::new_from_top(hub)
/ 或者原生构造函数重载native constructor overloads
:通过克隆另一个 hub
的顶部堆栈top stack
来创建新的 hub
。get_current_hub()
/ Hub::current()
/ Hub::get_current()
:全局函数或静态函数以返回当前(线程的)hub
。get_main_hub()
/ Hub::main()
/ Hub::get_main()
:在主线程main thread
是特殊的语言中(“Thread bound hub”
模型),这会返回 main thread
的中心而不是当前线程 current thread
的中心。这可能并不存在于所有的语言中。Hub::capture_event
/ Hub::capture_message
/ Hub::capture_exception
:捕获 message / exception
到 capture event
。capture_event
将传递的 event
与 scope
数据合并,并分派给 client
。作为附加参数,它还需要一个提示。有关 hint
参数,请参见 hints
。Hub::push_scope()
:推送一个继承前一个数据的新作用域层new scope layer
。这应返回有意义的语言的 disposable
或 stack guard
。当使用 “内部作用域中心”internally scoped hub
并发模型时,通常需要对此进行调用,否则可能会意外地错误共享作用域。Hub::with_scope(callback)
(optional):在 Python
中,这可能是上下文管理器;在 Ruby
中,这可能是块函数。推动并弹出集成工作的 scope
。Hub::pop_scope(callback)
(optional):只存在于没有更好的资源管理resource management
的语言中。最好在 push_scope
的返回值上使用这个函数,或者使用 with_scope
。这有时也被称为 pop_scope_unsafe
,以表明不应该直接使用该方法。Hub::configure_scope(callback)
:使用对修改范围的可变引用来调用回调。这也可以是具有它的语言(Python
)中的 with
语句。如果没有 active client
绑定到该 hub
,则 SDK
不应调用回调。Hub::add_breadcrumb(crumb, hint)
:将面包屑添加到当前作用域。raw breadcrumb object
应该被接受。active client
绑定到该 hub
,则 SDK
应忽略面包屑。hint
参数,请参见 hints
。Hub::client() / Hub::get_client()
(optional):返回当前 client
或 None
的 Accessor
或 getter
。Hub::bind_client(new_client)
:将不同的 client
绑定到 hub
。如果 hub
也是 init
创建的 client
的所有者,那么如果 hub
是负责处理它的对象,则需要保留对它的引用。Hub::unbind_client()
(optional):对于 bind_client
不接受空值的语言,可选的解绑定方法。Hub::last_event_id()
:应该返回当前 scope
发出的最后一个 event ID
。例如,这是用来实现用户反馈对话框feedback dialogs
。Hub::run(hub, callback) hub.run(callback), run_in_hub(hub, callback)
(optional):运行将 hub
绑定为当前 hub
的回调。scope
包含了应该与 Sentry
事件一起隐式发送的数据。它可以保存上下文数据context data
、额外参数extra parameters
、级别覆盖level overrides
、指纹fingerprints
等。
用户可以通过全局函数 configure_scope
修改当前作用域(设置额外的、标记、当前用户)。configure_scope
接受一个回调函数,并将当前的作用域传递给它。
使用这种基于回调的 API
的原因是效率。如果禁用了 SDK
,它就不应该调用回调函数,从而避免不必要的工作。
Sentry.configureScope(scope =>
scope.setExtra("character_name", "Mighty Fighter"));
scope.set_user(user)
:浅合并用户 Shallow merges
配置(电子邮件email
,用户名username
等)。删除用户数据是 SDK 定义的,可以使用 remove_user
函数,也可以不传递任何数据。scope.set_extra(key, value)
:将附加键设置为任意值,覆盖潜在的先前值。删除 key
是 SDK
定义的,可以使用 remove_extra
函数或不传递任何数据作为数据。这是不推荐使用的功能,应鼓励用户改用上下文。scope.set_extras(extras)
:设置一个具有 key/value
对,便捷功能的对象,而不是多个 set_extra
调用。与 set_extra
一样,这被视为已弃用的功能。scope.set_tag(key, value)
:将 tag
设置为字符串值,覆盖潜在的先前值。删除 key
是 SDK
定义的,可以使用 remove_tag
函数或不传递任何数据作为数据。scope.set_tags(tags)
:设置一个具有 key/value
对,便捷功能的对象,而不是多个 set_tag
调用。scope.set_context(key, value)
:将上下文键设置为一个值,覆盖一个潜在的先前值。删除 key
是 SDK
定义的,可以使用 remove_context
函数或不传递任何数据作为数据。这些类型是 sdk
指定的。scope.set_level(level)
:设置在此 scope
内发送的所有事件的级别。scope.set_transaction(transaction_name)
:设置当前 transaction
的名称。scope.set_fingerprint(fingerprint[])
:将指纹设置为将特定事件分组在一起。scope.add_event_processor(processor)
:注册事件处理器函数 event processor
。它接受一个事件并返回一个新事件,或者返回 None
来将其删除。这是许多集成的基础。scope.add_error_processor(processor)
(optional):注册错误处理器函数。它接受一个事件和异常对象,并返回一个新事件或“None”
将其删除。这可用于从 SDK
无法提取自身的异常对象中提取其他信息。scope.clear()
:将 scope
重置为默认值,同时保留所有已注册的事件处理器event processors
。这不会影响子作用域或父作用域。scope.add_breadcrumb(breadcrumb)
:将面包屑添加到当前 scope
。scope.clear_breadcrumbs()
:从 scope
中删除当前的面包屑 breadcrumbs
。scope.apply_to_event(event[, max_breadcrumbs])
:将 scope
数据应用于给定的事件对象。这也适用于内部存储在 scope
中的事件处理器 event processors
。一些实现可能想要在此处设置最大面包屑计数。Client
是 SDK
中负责事件创建的部分。例如,Client
应将异常转换为 Sentry event
。Client
应该是无状态的,它会注入作用域并委托将事件发送到 Transport
的工作。
Client::from_config(config)
:(或者是普通的构造函数)这通常采用带有 options + dsn
的对象。Client::capture_event(event, scope)
:通过将事件与其他数据(client
默认设置)合并来捕获事件。另外,如果将 scope
传递到此系统,则来自该范围的数据会将其传递到内部 transport
。Client::close(timeout)
:刷新队列直到超时秒。如果客户端能够保证事件的交付仅持续到当前时间点,则首选此方法。这可能会因为超时秒而阻塞。在调用 close
后,客户端应该被禁用或销毁。Client::flush(timeout)
:和 close
的区别一样,客户端在调用 flush
后不会被释放。(可选)支持事件捕获和面包屑添加的附加参数:hint
。
hint
是特定于 SDK
的,但提供了关于事件起源的高级信息。例如,如果捕获了一个异常,提示可能携带原始异常对象。并不是所有的 SDK
都需要提供这个功能。然而,这个参数是为此目的保留的。
capture_event
捕获的事件将按以下顺序处理。
注意:事件可以在任何阶段丢弃,此时不会发生进一步的处理。
SDK
, Sentry
会立即丢弃该事件。apply_to_event
应用该作用域。按顺序调用作用域的事件处理器。Sentry
调用 before-send
钩子。Sentry
将事件传递到配置的 transport
。如果传输没有有效的 DSN
,则可以丢弃该事件;它的内部队列已满;或由于服务器要求的速率限制。许多选项都是跨 SDK
标准化的。有关这些选项的列表,请参阅 the main options documentation
。