Span
编辑Span
编辑Span 包含有关特定代码路径执行的信息。它们衡量从一个活动开始到结束的时间,并且可以与其他 span 具有父/子关系。
代理会自动检测各种库以捕获应用程序中的这些 span,但您也可以使用代理 API 对特定代码路径进行自定义检测。
除此之外,span 可以包含
- 一个
transaction.id
属性,该属性引用其父 事务。 - 一个
parent.id
属性,该属性引用其父 span 或事务。 - 它的开始时间和持续时间。
- 一个
name
、type
、subtype
和action
— 请参阅 span 名称/类型对齐表,了解按 APM 代理划分的 span 名称模式和示例。此外,一些 APM 代理会针对公共的 span 类型/子类型规范进行测试。 - 一个可选的
堆栈跟踪
。堆栈跟踪由堆栈帧组成,堆栈帧表示调用堆栈上的函数调用。它们包括函数名称、文件名和路径、行号等属性。
大多数代理将关键字字段(如 span.id
)限制为 1024 个字符,并将非关键字字段(如 span.start.us
)限制为 10,000 个字符。
丢弃的 span
编辑出于性能原因,APM 代理可以选择采样或有意省略 span。这有助于防止边缘情况,例如超过 100 个 span 的长时间运行的事务,否则会使代理和 APM Server 都过载。发生这种情况时,应用程序 UI 将显示丢弃的 span 数量。
要配置每个事务记录的 span 数量,请参阅相关的代理文档
- Android: 尚未支持
- Go:
ELASTIC_APM_TRANSACTION_MAX_SPANS
- iOS: 尚未支持
- Java:
transaction_max_spans
- .NET:
TransactionMaxSpans
- Node.js:
transactionMaxSpans
- PHP:
transaction_max_spans
- Python:
transaction_max_spans
- Ruby:
transaction_max_spans
丢失的 span
编辑代理将 span 与其事务分开流式传输到 APM Server。因此,不可预见的错误可能会导致 span 丢失。代理知道一个事务应该有多少个 span;如果预期 span 的数量不等于 APM Server 收到的 span 的数量,应用程序 UI 将计算差值并显示一条消息。
数据流
编辑Span 与事务一起存储在以下数据流中
- 应用程序跟踪:
traces-apm-<namespace>
- RUM 和 iOS 代理应用程序跟踪:
traces-apm.rum-<namespace>
请参阅 数据流 以了解更多信息。
Span 文档示例
编辑此示例显示了在 Elasticsearch 中索引时 span 文档的样子。
展开 Elasticsearch 文档
[ { "@timestamp": "2017-05-30T18:53:27.154Z", "agent": { "name": "elastic-node", "version": "3.14.0" }, "ecs": { "version": "1.12.0" }, "event": { "outcome": "unknown" }, "http": { "request": { "method": "GET" }, "response": { "status_code": 200 } }, "labels": { "span_tag": "something" }, "observer": { "hostname": "ix.lan", "type": "apm-server", "version": "8.0.0" }, "parent": { "id": "945254c567a5417e" }, "processor": { "event": "span", "name": "transaction" }, "service": { "environment": "staging", "name": "1234_service-12a3" }, "span": { "action": "query", "db": { "instance": "customers", "statement": "SELECT * FROM product_types WHERE user_id=?", "type": "sql", "user": { "name": "readonly_user" } }, "duration": { "us": 3781 }, "http": { "method": "GET", "response": { "status_code": 200 } }, "http.url.original": "https://127.0.0.1:8000", "id": "0aaaaaaaaaaaaaaa", "name": "SELECT FROM product_types", "stacktrace": [ { "abs_path": "net.js", "context": { "post": [ " ins.currentTransaction = prev", " return result", "}" ], "pre": [ " var trans = this.currentTransaction", "" ] }, "exclude_from_grouping": false, "filename": "net.js", "function": "onread", "library_frame": true, "line": { "column": 4, "context": "line3", "number": 547 }, "module": "some module", "vars": { "key": "value" } }, { "exclude_from_grouping": false, "filename": "my2file.js", "line": { "number": 10 } } ], "start": { "us": 2830 }, "subtype": "postgresql", "sync": false, "type": "db" }, "timestamp": { "us": 1496170407154000 }, "trace": { "id": "945254c567a5417eaaaaaaaaaaaaaaaa" }, "transaction": { "id": "945254c567a5417e" }, "url": { "original": "https://127.0.0.1:8000" } }, { "@timestamp": "2017-05-30T18:53:42.281Z", "agent": { "name": "js-base", "version": "1.3" }, "destination": { "address": "0:0::0:1", "ip": "0:0::0:1", "port": 5432 }, "ecs": { "version": "1.12.0" }, "event": { "outcome": "unknown" }, "observer": { "ephemeral_id": "2f13d8fa-83cd-4356-8123-aabfb47a1808", "hostname": "goat", "id": "17ad47dd-5671-4c89-979f-ef4533565ba2", "type": "apm-server", "version": "8.0.0" }, "parent": { "id": "85925e55b43f4342" }, "processor": { "event": "span", "name": "transaction" }, "service": { "environment": "staging", "name": "serviceabc" }, "span": { "action": "query.custom", "db": { "instance": "customers", "statement": "SELECT * FROM product_types WHERE user_id=?", "type": "sql", "user": { "name": "readonly_user" } }, "destination": { "service": { "name": "postgresql", "resource": "postgresql", "type": "db" } }, "duration": { "us": 3781 }, "id": "15aaaaaaaaaaaaaa", "name": "SELECT FROM product_types", "start": { "us": 2830 }, "subtype": "postgresql", "type": "db.postgresql.query" }, "timestamp": { "us": 1496170422281000 }, "trace": { "id": "85925e55b43f4342aaaaaaaaaaaaaaaa" }, "transaction": { "id": "85925e55b43f4342" } }, { "@timestamp": "2017-05-30T18:53:27.154Z", "agent": { "name": "elastic-node", "version": "3.14.0" }, "ecs": { "version": "1.12.0" }, "event": { "outcome": "unknown" }, "observer": { "ephemeral_id": "2f13d8fa-83cd-4356-8123-aabfb47a1808", "hostname": "goat", "id": "17ad47dd-5671-4c89-979f-ef4533565ba2", "type": "apm-server", "version": "8.0.0" }, "parent": { "id": "945254c567a5417e" }, "processor": { "event": "span", "name": "transaction" }, "service": { "environment": "staging", "name": "1234_service-12a3" }, "span": { "duration": { "us": 32592 }, "id": "1aaaaaaaaaaaaaaa", "name": "GET /api/types", "start": { "us": 0 }, "subtype": "external", "type": "request" }, "timestamp": { "us": 1496170407154000 }, "trace": { "id": "945254c567a5417eaaaaaaaaaaaaaaaa" }, "transaction": { "id": "945254c567a5417e" } }, { "@timestamp": "2017-05-30T18:53:27.154Z", "agent": { "name": "elastic-node", "version": "3.14.0" }, "ecs": { "version": "1.12.0" }, "event": { "outcome": "unknown" }, "observer": { "ephemeral_id": "2f13d8fa-83cd-4356-8123-aabfb47a1808", "hostname": "goat", "id": "17ad47dd-5671-4c89-979f-ef4533565ba2", "type": "apm-server", "version": "8.0.0" }, "parent": { "id": "945254c567a5417e" }, "processor": { "event": "span", "name": "transaction" }, "service": { "environment": "staging", "name": "1234_service-12a3" }, "span": { "action": "post", "duration": { "us": 3564 }, "id": "2aaaaaaaaaaaaaaa", "name": "GET /api/types", "start": { "us": 1845 }, "subtype": "http", "type": "request" }, "timestamp": { "us": 1496170407154000 }, "trace": { "id": "945254c567a5417eaaaaaaaaaaaaaaaa" }, "transaction": { "id": "945254c567a5417e" } }, { "@timestamp": "2017-05-30T18:53:27.154Z", "agent": { "name": "elastic-node", "version": "3.14.0" }, "child": { "id": [ "4aaaaaaaaaaaaaaa" ] }, "ecs": { "version": "1.12.0" }, "event": { "outcome": "unknown" }, "observer": { "ephemeral_id": "2f13d8fa-83cd-4356-8123-aabfb47a1808", "hostname": "goat", "id": "17ad47dd-5671-4c89-979f-ef4533565ba2", "type": "apm-server", "version": "8.0.0" }, "parent": { "id": "945254c567a5417e" }, "processor": { "event": "span", "name": "transaction" }, "service": { "environment": "staging", "name": "1234_service-12a3" }, "span": { "duration": { "us": 13980 }, "id": "3aaaaaaaaaaaaaaa", "name": "GET /api/types", "start": { "us": 0 }, "type": "request" }, "timestamp": { "us": 1496170407154000 }, "trace": { "id": "945254c567a5417eaaaaaaaaaaaaaaaa" }, "transaction": { "id": "945254c567a5417e" } } ]
Span 压缩
编辑在某些情况下,APM 代理可能会在一个事务中收集大量非常相似或相同的 span。例如,如果在循环内捕获 span,或者在未优化的 SQL 查询中使用多个查询而不是连接来获取相关数据时,可能会发生这种情况。在这种情况下,每个事务的 span 上限(默认情况下为 500 个 span)可能会很快达到,导致代理停止捕获给定事务的潜在更相关的 span。
这种重复的相似 span 本身通常不是非常相关,尤其是当它们持续时间很短时。它们还会使 UI 变得混乱,并导致处理和存储开销。
为了解决这个问题,APM 代理可以将这些 span 压缩为一个 span。压缩后的 span 会保留大部分原始 span 信息,例如总持续时间和它表示的 span 数量。
无论压缩策略如何,如果满足以下条件,则 span 有资格进行压缩
- 它尚未传播其跟踪上下文。
- 是一个退出 span(例如数据库查询 span)。
- 其结果不是
"failure"
。
APM 代理可以在两个策略之间选择,以确定是否可以压缩两个相邻的 span。这两个策略的好处是,只需要在内存中保留一个先前的 span。这对于确保代理不需要大量内存来启用 span 压缩非常重要。
如果两个相邻的 span 具有相同的
- span 类型
- span 子类型
-
destination.service.resource
(例如,数据库名称)
如果两个相邻的 span 具有相同的
- span 名称
- span 类型
- span 子类型
-
destination.service.resource
(例如,数据库名称)
代理具有配置设置,用于定义这两种策略的 span 持续时间上限阈值。“同类”策略的默认限制为 0 毫秒,这意味着默认情况下禁用“同类”策略。“精确匹配”策略的默认限制为 50 毫秒。持续时间较长的 span 不会被压缩。有关详细信息,请参阅代理文档。
以下代理支持 span 压缩
代理 | 同类配置 | 精确匹配配置 |
---|---|---|
Go 代理 |
||
Java 代理 |
||
.NET 代理 |
||
Node.js 代理 |
||
Python 代理 |