Selenium Grid 中的可观测性
目录
Selenium Grid
Grid 通过在各种浏览器和操作系统组合上执行测试来帮助扩展和分发测试。
可观测性
可观测性有三个支柱:追踪、指标和日志。由于 Selenium Grid 4 被设计为完全分布式的,因此可观测性将更容易理解和调试内部结构。
分布式追踪
单个请求或事务跨越多个服务和组件。追踪会在每个服务执行请求时跟踪请求的生命周期。这在错误场景中进行调试非常有用。在追踪上下文中用到的一些关键术语是
追踪 追踪允许人们通过多个服务追踪一个请求,从其起点到最终目的地。这个请求的旅程有助于调试、监控端到端流程以及识别故障。追踪描述了端到端的请求流程。每个追踪都有一个唯一的 ID 作为其标识符。
跨度 每个追踪都由称为跨度的定时操作组成。一个跨度具有开始和结束时间,它表示服务执行的操作。跨度的粒度取决于它的工具化方式。每个跨度都有一个唯一的标识符。一个追踪中的所有跨度具有相同的追踪 ID。
跨度属性 跨度属性是键值对,它们提供关于每个跨度的附加信息。
事件 事件是跨度内的带时间戳的日志。它们为现有的跨度提供了额外的上下文。事件还包含键值对作为事件属性。
事件日志
日志对于调试应用程序至关重要。日志通常以人类可读的格式完成。但是,为了使机器搜索和分析日志,它必须具有定义良好的格式。结构化日志是一种以固定格式一致地记录日志的常见实践。它通常包含如下字段:
- 时间戳
- 日志级别
- 日志类
- 日志消息(这进一步分解为与记录日志的操作相关的字段)
日志和事件密切相关。事件封装了执行单个工作单元的所有可用信息。日志本质上是事件的子集。从根本上讲,两者都有助于调试。有关详细的理解,请参考以下资源
- https://www.honeycomb.io/blog/how-are-structured-logs-different-from-events/
- https://charity.wtf/2019/02/05/logs-vs-structured-events/
Grid 可观测性
Selenium 服务器使用 OpenTelemetry 进行追踪工具化。对服务器的每个请求都从开始到结束进行追踪。当请求在服务器内执行时,每个追踪都由一系列跨度组成。Selenium 服务器中的大多数跨度都包含两个事件
- 正常事件 - 记录关于一个工作单元的所有信息,并标记该工作已成功完成。
- 错误事件 - 记录直到发生错误时的所有信息,然后记录错误信息。标记异常事件。
运行 Selenium 服务器
可视化追踪
所有跨度、事件及其各自的属性都是追踪的一部分。在上述所有模式下运行服务器时,追踪都可以工作。
默认情况下,Selenium 服务器中启用了追踪。Selenium 服务器通过两个导出器导出追踪
- 控制台 - 在 FINE 级别记录所有追踪及其包含的跨度。默认情况下,Selenium 服务器在 INFO 级别及以上级别打印日志。**log-level** 标志可用于在运行 Selenium Grid jar/s 时传递所选的日志级别。
java -jar selenium-server-4.0.0-<selenium-version>.jar standalone --log-level FINE
- Jaeger UI - OpenTelemetry 提供了在代码中工具化追踪的 API 和 SDK。而 Jaeger 是一个追踪后端,它有助于收集追踪遥测数据,并为数据提供查询、过滤和可视化功能。
可以通过运行以下命令获得使用 Jaeger UI 可视化追踪的详细说明
java -jar selenium-server-4.0.0-<selenium-version>.jar info tracing
一个非常好的示例和脚本,用于运行服务器并将追踪发送到 Jaeger
利用事件日志
即使不希望导出追踪以进行可视化,也必须启用追踪才能进行事件记录。
默认情况下,已启用追踪。无需传递额外的参数即可在控制台上查看日志。 跨度内的所有事件都记录在 FINE 级别。错误事件记录在 WARN 级别。
所有事件日志都有以下字段
字段 | 字段值 | 描述 |
---|---|---|
事件时间 | eventId | 事件记录的时间戳(以纪元纳秒为单位)。 |
追踪 ID | tracedId | 每个追踪都由一个唯一的追踪 ID 标识。 |
跨度 ID | spanId | 一个追踪中的每个跨度都由一个唯一的跨度 ID 标识。 |
跨度类型 | spanKind | 跨度类型是跨度的一个属性,指示跨度的类型。它有助于理解跨度所完成的工作单元的性质。 |
事件名称 | eventName | 这映射到日志消息。 |
事件属性 | eventAttributes | 这是事件日志的核心,基于执行的操作,它具有 JSON 格式的键值对。它还包括一个处理程序类属性,以显示日志类。 |
示例日志
FINE [LoggingOptions$1.lambda$export$1] - {
"traceId": "fc8aef1d44b3cc8bc09eb8e581c4a8eb",
"spanId": "b7d3b9865d3ddd45",
"spanKind": "INTERNAL",
"eventTime": 1597819675128886121,
"eventName": "Session request execution complete",
"attributes": {
"http.status_code": 200,
"http.handler_class": "org.openqa.selenium.grid.router.HandleSession",
"http.url": "\u002fsession\u002fdd35257f104bb43fdfb06242953f4c85",
"http.method": "DELETE",
"session.id": "dd35257f104bb43fdfb06242953f4c85"
}
}
除了上述字段外,基于 OpenTelemetry 规范,错误日志由以下组成
字段 | 字段值 | 描述 |
---|---|---|
异常类型 | exception.type | 异常的类名。 |
异常消息 | exception.message | 异常的原因。 |
异常堆栈跟踪 | exception.stacktrace | 打印抛出异常时的调用堆栈。有助于理解异常的来源。 |
示例错误日志
WARN [LoggingOptions$1.lambda$export$1] - {
"traceId": "7efa5ea57e02f89cdf8de586fe09f564",
"spanId": "914df6bc9a1f6e2b",
"spanKind": "INTERNAL",
"eventTime": 1597820253450580272,
"eventName": "exception",
"attributes": {
"exception.type": "org.openqa.selenium.ScriptTimeoutException",
"exception.message": "Unable to execute request: java.sql.SQLSyntaxErrorException: Table 'mysql.sessions_mappa' doesn't exist ..." (full message will be printed),
"exception.stacktrace": "org.openqa.selenium.ScriptTimeoutException: java.sql.SQLSyntaxErrorException: Table 'mysql.sessions_mappa' doesn't exist\nBuild info: version: '4.0.0-alpha-7', revision: 'Unknown'\nSystem info: host: 'XYZ-MacBook-Pro.local', ip: 'fe80:0:0:0:10d5:b63a:bdc6:1aff%en0', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.6', java.version: '11.0.7'\nDriver info: driver.version: unknown ...." (full stack will be printed),
"http.handler_class": "org.openqa.selenium.grid.distributor.remote.RemoteDistributor",
"http.url": "\u002fsession",
"http.method": "POST"
}
}
注意:上面的日志为了便于阅读进行了格式化。在 Selenium 服务器中关闭了日志的格式化。
上述步骤应该可以帮助您查看追踪和日志。