注意
采样替代功能已正式发布(从 3.5.0. 开始提供)。
采样替代允许你替代默认采样百分比,例如:
- 将采样百分比设置为 0(或某个小值)以检查干扰运行状况。
- 将采样百分比设置为 0(或一个较小的值),以用于噪声依赖调用。
- 对于重要的请求类型(例如,
/login
),将采样百分比设置为 100,即使默认的采样配置为低于此值也是如此。
术语
在了解采样替代之前,应了解术语“范围”。 跨度是一个通用术语,指:
- 传入的请求。
- 传出的依赖项(例如,对另一个服务的远程调用)。
- 进程内依赖项(例如,由服务的子组件所做的工作)。
对于采样替代而言,这些范围组件非常重要:
- 属性
范围属性表示给定请求或依赖项的标准属性和自定义属性。
入门
首先,创建一个名为“applicationinsights.json”的配置文件。 将其保存在与“applicationinsights-agent-*.jar”相同的目录中。 请使用以下模版。
{
"connectionString": "...",
"sampling": {
"percentage": 10,
"overrides": [
{
"telemetryType": "request",
"attributes": [
...
],
"percentage": 0
},
{
"telemetryType": "request",
"attributes": [
...
],
"percentage": 100
}
]
}
}
工作原理
telemetryType
(Application Insights 3.4.0 中的 telemetryKind
) 必须是 request
、dependency
、trace
(日志) 或 exception
。
当开始一个范围时,会使用该范围的类型以及当时存在于其上的属性来检查是否有任何匹配的采样替代。
匹配项可为 strict
或 regexp
。 正则表达式匹配是针对整个属性值执行的,因此如果要匹配其中任何位置包含 abc
的值,则需要使用 .*abc.*
。
采样替代可以指定多个属性条件,在这种情况下,所有属性条件都必须匹配,才能使采样替代匹配。
如果有一个采样替代匹配,则使用其采样百分比来确定是否要对该范围采样。
只使用匹配的第一个采样替代。
如果没有采样替代匹配:
- 如果是跟踪中的第一个跨段,则使用顶级采样配置。
- 如果不是跟踪中的第一个范围,则会使用父采样决策。
可用于采样的范围属性
OpenTelemetry 范围属性为自动收集,且基于 OpenTelemetry 语义约定。
你还能以编程方式添加范围属性,并将其用于采样。
注意
若要查看 Application Insights Java 为应用程序捕获的确切属性集,请将自诊断级别设置为调试,并查找以文本“导出 Span”开头的调试消息。
注意
只有范围开始时设置的属性可用于采样,因此 http.response.status_code
或稍后捕获的请求持续时间等属性可以通过 OpenTelemetry Java 扩展进行筛选。 下面是一个示例扩展,它根据请求持续时间筛选范围。
注意
使用遥测处理器添加的属性不可用于采样。
用例
抑制对运行状况检查的遥测数据的收集
这一示例会取消收集所有对 /health-checks
的请求的遥测数据。
此示例也会抑制通常会在 /health-checks
下收集的任何下游范围(依赖项)的收集。
{
"connectionString": "...",
"sampling": {
"overrides": [
{
"telemetryType": "request",
"attributes": [
{
"key": "url.path",
"value": "/health-check",
"matchType": "strict"
}
],
"percentage": 0
}
]
}
}
抑制干扰依赖项调用的遥测数据的收集
此示例会抑制为所有 GET my-noisy-key
redis 调用收集遥测。
{
"connectionString": "...",
"sampling": {
"overrides": [
{
"telemetryType": "dependency",
"attributes": [
{
"key": "db.system",
"value": "redis",
"matchType": "strict"
},
{
"key": "db.statement",
"value": "GET my-noisy-key",
"matchType": "strict"
}
],
"percentage": 0
}
]
}
}
为重要请求类型收集 100% 的遥测
这一示例会收集 /login
的全部遥测数据。
由于下游范围(依赖项)遵循父级的采样决策(缺少该下游范围的任何采样替代),因此也会为所有“/login”请求收集这些范围。
{
"connectionString": "...",
"sampling": {
"percentage": 10
},
"sampling": {
"overrides": [
{
"telemetryType": "request",
"attributes": [
{
"key": "url.path",
"value": "/login",
"matchType": "strict"
}
],
"percentage": 100
}
]
}
}
公开范围属性以禁止 SQL 依赖项调用
此示例逐步讲解查找可用属性以抑制干扰 SQL 调用的体验。 以下查询描述了过去 30 天内的不同 SQL 调用和关联的记录计数:
dependencies
| where timestamp > ago(30d)
| where name == 'SQL: DB Query'
| summarize count() by name, operation_Name, data
| sort by count_ desc
SQL: DB Query POST /Order DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar; 36712549
SQL: DB Query POST /Receipt DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar; 2220248
SQL: DB Query POST /CheckOutForm DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar; 554074
SQL: DB Query GET /ClientInfo DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar; 37064
从结果中可以观察到,所有操作在data
字段中共享相同的值:DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;
。 所有这些记录之间的共性使其成为采样替代的一个不错的选择。
通过将自我诊断设置为调试,输出中会显示以下日志条目:
2023-10-26 15:48:25.407-04:00 DEBUG c.m.a.a.i.exporter.AgentSpanExporter - exporting span: SpanData{spanContext=ImmutableSpanContext...
这些日志中感兴趣的区域是“属性”部分:
{
"attributes": {
"data": {
"thread.name": "DefaultDatabaseBroadcastTransport: MessageReader thread",
"thread.id": 96,
"db.connection_string": "apache:",
"db.statement": "DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;",
"db.system": "other_sql",
"applicationinsights.internal.item_count": 1
}
}
}
使用该输出,您可以配置类似于以下示例的采样覆写,以筛选噪声 SQL 调用:
{
"connectionString": "...",
"preview": {
"sampling": {
"overrides": [
{
"telemetryType": "dependency",
"attributes": [
{
"key": "db.statement",
"value": "DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;",
"matchType": "strict"
}
],
"percentage": 0
}
]
}
}
}
应用更改后,以下查询允许我们确定这些依赖项上次引入 Application Insights 的时间:
dependencies
| where timestamp > ago(30d)
| where data contains 'DECLARE @MyVar'
| summarize max(timestamp) by data
| sort by max_timestamp desc
DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar; 11/13/2023 8:52:41 PM
抑制日志遥测数据的收集
使用 SL4J,可以添加日志属性:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
public class MdcClass {
private static final Logger logger = LoggerFactory.getLogger(MdcClass.class);
void method {
MDC.put("key", "value");
try {
logger.info(...); // Application log to remove
finally {
MDC.remove("key"); // In a finally block in case an exception happens with logger.info
}
}
}
然后,可以删除包含所添加的属性的日志:
{
"sampling": {
"overrides": [
{
"telemetryType": "trace",
"percentage": 0,
"attributes": [
{
"key": "key",
"value": "value",
"matchType": "strict"
}
]
}
]
}
}
禁止收集 Java 方法的遥测数据
我们将向 Java 方法添加一个跨度,然后通过采样覆盖来删除这个跨度。
我们首先添加 opentelemetry-instrumentation-annotations
依赖项:
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-annotations</artifactId>
</dependency>
现在,我们可以将 WithSpan
注释添加到执行 SQL 请求的 Java 方法:
package org.springframework.samples.petclinic.vet;
@Controller
class VetController {
private final VetRepository vetRepository;
public VetController(VetRepository vetRepository) {
this.vetRepository = vetRepository;
}
@GetMapping("/vets.html")
public String showVetList(@RequestParam(defaultValue = "1") int page, Model model) {
Vets vets = new Vets();
Page<Vet> paginated = findPaginated(page);
vets.getVetList().addAll(paginated.toList());
return addPaginationModel(page, paginated, model);
}
@WithSpan
private Page<Vet> findPaginated(int page) {
int pageSize = 5;
Pageable pageable = PageRequest.of(page - 1, pageSize);
return vetRepository.findAll(pageable); // Execution of SQL requests
}
以下采样替代配置可用于删除由 WithSpan
注释添加的范围:
"sampling": {
"overrides": [
{
"telemetryType": "dependency",
"attributes": [
{
"key": "code.function",
"value": "findPaginated",
"matchType": "strict"
}
],
"percentage": 0
}
]
}
属性值是 Java 方法的名称。
此配置删除从 findPaginated
方法创建的所有遥测数据。 不会为来自 findPaginated
该方法的 SQL 执行创建 SQL 依赖项。
以下配置删除从具有WithSpan
批注的VetController
类方法发出的所有遥测数据:
"sampling": {
"overrides": [
{
"telemetryType": "dependency",
"attributes": [
{
"key": "code.namespace",
"value": "org.springframework.samples.petclinic.vet.VetController",
"matchType": "strict"
}
],
"percentage": 0
}
]
}
故障排除
如果使用了 regexp
,而采样替代不起作用,请尝试使用 .*
正则表达式。 如果采样现在起作用,则表示第一个正则表达式有问题,请阅读此正则表达式文档。
如果它不适用于 .*
,则 application-insights.json file
中可能存在语法问题。 请查看 Application Insights 日志,留意是否存在警告消息。
常见问题
是否需要使用手动检测来启用采样替代?
不需要,采样替代现已正式发布 (GA),同时适用自动检测和手动检测。
将 Azure 应用服务与自动检测结合应用时如何配置采样替代?
如果使用自动探针,请更新 Azure 门户中的 applicationinsights.json
文件。
是否需要手动上传用于采样替代的 Application Insights 代理文件?
对于自动检测,无需手动上传代理。 但是,对于手动检测,仍需要在部署包中包含 Application Insights 代理 JAR 文件和配置文件。
手动检测上下文中的“本地开发”和“应用程序服务器”有何区别?
本地开发是指正在生成或测试应用的环境,例如开发人员计算机。 应用程序服务器是指运行应用程序的 Web 服务器,例如 Azure 应用服务环境中的 Tomcat 11。 使用手动检测时,必须确保代理 JAR 文件正确放置在应用程序服务器上。
如果我在 Java 运行时(例如 Tomcat 11)中使用 Azure 应用服务,如何配置采样替代?
对于自动检测,可以通过 Azure 门户配置采样替代。 如果使用手动检测,则应将 Application Insights 代理 JAR 放在相应的目录中,并将 applicationinsights.json 文件与所需的采样设置一起包含在内。