你的 AI agent 需要一个不在场证明:Elastic 中 Agent Builder 的可观测性和审计追踪

作者:来自 Elastic Jeffrey Rengifo

Elastic 9.5 会将每次 Agent Builder 运行记录为你自己的集群中的 OpenTelemetry spans,因此 工具调用 和 token 数量都可以通过 ES|QL 进行查询。只需一个工作流步骤即可添加审批记录,并将其写入一个管道无法重写的数据流中。

向一个 Elastic Agent Builder agent 提出一个问题,产生了 24 个 spans,涉及两个模型的 10 次模型调用,以及大约 160,000 个输入 token。Elastic 9.5 无需 collector 或 scraper 即可记录 AI agent 可观测性数据。默认情况下,每次运行都会作为 OpenTelemetry traces 写入你自己的集群,写入 traces-agent_builder.otel-<space-id>,细化到 agent 生成的每个 ES|QL 查询以及它查询的每个索引。

这些 traces 展示了 agent 如何得出建议以及产生了多少成本,但不会记录是谁批准了它。下面介绍如何读取这些 traces、确定一次运行涉及的三个身份,以及如何将审批决定追加到一个管道无法重写的数据流中。

前提条件

  • Elastic Stack 9.5 或 Serverless

  • 具有管理 Kibana 高级设置的权限,这是安装 traces 仪表板所必需的。

Elastic Observability 在哪里记录 AI agent 操作的各个部分

每次审查 agent 化运营管道时,都会出现四个问题,而每个问题都由不同的记录来回答。

问题 答案所在位置 创建者
agent 是如何得出建议的? traces-agent_builder.otel-* spans Agent Builder,自动生成
它调用了哪些工具,以及这些工具是否失败? 同一数据流中的 execute_tool spans Agent Builder,自动生成
此次运行使用了谁的权限? 工作流执行记录和 Elasticsearch 安全审计日志 Kibana,部分记录
人类做出了什么决定,以及操作是否执行? 由你自己写入的索引

前两个功能在 9.5 中是新增的,只需启用一个开关,无需额外费用。最后一个没有自动记录来源,因此也是大多数管道所缺失的部分。

场景:结账流程中的过期定价缓存

三个 checkout-service worker 为生产流量提供服务。其中一个,即 checkout-worker-1,已经升级到版本 2026.07.26.1,现在每次获取报价都会返回 HTTP 500,因为它的定价缓存停止刷新。其他两个仍运行 2026.07.25.3 版本,并正常提供服务。

这一设置背后的 SRE 控制平面模式,将遥测数据、基于这些数据进行推理的 Agent Builder agent,以及执行已知操作的 Elastic Workflows 连接起来,并在第一个会修改生产环境的步骤之前设置人工审批闸门

遥测数据通过文档中介绍的 OpenTelemetry 路径传入,因此 agent 可以读取标准 OTel 字段。Elasticsearch 9.5 提供原生 OTLP 端点,使 OTel SDK 可以直接将数据写入集群,中间无需 collector:

python 复制代码
`

1.  from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
2.  from opentelemetry.sdk._logs import LoggerProvider
3.  from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
4.  from opentelemetry.sdk.resources import Resource

6.  provider = LoggerProvider(
7.      resource=Resource.create({
8.          "service.name": "checkout-service",
9.          "deployment.environment": "production",
10.      })
11.  )
12.  provider.add_log_record_processor(
13.      BatchLogRecordProcessor(
14.          OTLPLogExporter(
15.              endpoint=f"{ES_URL}/_otlp/v1/logs",
16.              headers={"Authorization": f"ApiKey {API_KEY}"},
17.          )
18.      )
19.  )

`Lobster AI![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

该端点通过 protobuf 使用 OTLP,并且会对 application/json 返回 HTTP 406,因此应该通过 SDK 或 collector 发送,而不是手动构建 JSON。这会向 logs-generic.otel-default 写入 450 条记录:三个 worker 中共有 360 条正常事件,以及来自故障 worker 的 90 条 PricingCacheStaleError 事件。agent 不会获得这些上下文中的任何信息,而必须通过查询自行找到这些信息。

在 Elastic 中读取 AI agent 可观测性 traces

Agent Builder 记录的与一次运行有关的所有信息都存储在两个数据流中,并且全部可以通过 ES|QL 进行查询。

如何在 GenAI 设置中启用 AI agent tracing

打开 Stack Management ,然后打开 GenAI Settings ,找到 Agent Builder Traces 部分。在 9.5 中,Collect conversation traces 默认处于启用状态。

该面板中有两个细节比开关本身更重要。traces 会写入 traces-agent_builder.otel-<space-id>,每个 Kibana space 对应一个数据流,同时还有一个配套的 logs-agent_builder.otel-<space-id>,用于记录 agent 侧的事件。这些都是使用标准 OTel 索引模板的普通数据流,而不是隐藏的系统索引,因此 Discover、Lens 和 ES|QL 都可以直接查询它们。

提示信息明确说明了访问模型:任何能够读取该索引的人,都可以读取其中的所有 trace。Trace 访问权限不会按用户进行限制,因此在向包含敏感对话的 space 授予访问权限之前,应通过角色限制索引模式。

读取一次 agent 运行的 LLM trace 瀑布图

通过 converse API 提出一个问题,让内置的 Elastic AI Agent 调查 logs-generic.otel-default,找出哪些 pod 和版本返回 HTTP 500,并提出一个范围受限的操作。它正确地给出了答案,指出 checkout-worker-1 的版本为 2026.07.26.1,错误率为 43%,而仍运行 2026.07.25.3 的另外两个 worker 没有错误。

在任意 agent 响应下方选择 trace 图标,即可打开瀑布图。

通过 converse API 提出的一个问题产生了 24 个 spans,耗时 43.7 秒。其结构是一个 invoke_agent 根 span、一个 generate_title 分支,然后交替出现 chatexecute_tool spans,agent 在查询、读取结果以及选择下一次查询的过程中依次产生这些 spans。

三个 span 系列包含了你需要进行聚合的所有信息。

Span 名称前缀 表示内容 关键属性
invoke_agent 一轮对话(CHAIN)或一次 agent 执行(AGENT elastic.inference.span.kindgen_ai.agent.id
chat 一次模型调用 gen_ai.request.modelgen_ai.provider.namegen_ai.usage.input_tokensgen_ai.usage.output_tokens
execute_tool 一次工具调用 gen_ai.tool.namegen_ai.tool.call.idstatus.code

这次运行的 token 分解如下:

模型 调用次数 输入 token 输出 token
anthropic-claude-4.6-sonnet 5 113,315 2,039
anthropic-claude-4.5-haiku 5 47,211 651

一半的模型调用使用了较小的模型。这就是快速模型路由,它会将低工作量的步骤发送到成本更低的模型,而这种模型分配情况只有在 trace 中才能看到。

这次单独的 agent 调查总共消耗了大约 160,000 个输入 token。每一轮都会重新处理累积的上下文,因此成本会随着对话长度增长,而不是随着问题本身的长度增长。

如何使用 ES|QL 查询 agent 的工具调用?

工具调用是最值得关注的 agent 行为部分,因为 agent 正是在这里接触你的数据。每次调用都会产生一个 execute_tool span,而文档中的查询可以直接对这些调用进行聚合:

sql 复制代码
`

1.  FROM traces-agent_builder.otel-*
2.  | WHERE span.name LIKE "execute_tool *"
3.  | STATS calls = COUNT(*),
4.          errors = COUNT(*) WHERE status.code == "Error",
5.          avg_ms = ROUND(AVG(duration) / 1000000.0, 1)
6.    BY tool = attributes.gen_ai.tool.name
7.  | SORT calls DESC

`Lobster AI

在这次运行中,agent 主要使用了 platform.core.execute_esql,而其背后的 platform.core.generate_esqlload_skill 各调用了两次。文档根部的 duration 单位是纳秒,这也是查询需要除以一百万来转换为毫秒的原因。

同时也要检查配套的 logs 数据流。在同一会话的另一次运行中,agent 尝试调用一个不在其可用工具集合中的工具,这次尝试被记录为 logs-agent_builder.otel-default 中的一个异常事件,并通过 trace_id 与该 trace 关联:

swift 复制代码
`

1.  {
2.    "trace_id": "3f8b9722dbd371ac4b7ad75e4bed13b6",
3.    "event_name": "exception",
4.    "attributes": {
5.      "exception.type": "toolNotFoundError",
6.      "exception.message": "Tool \"platform.streams.query_documents\" called but was not available"
7.    }
8.  }

`Lobster AI

一次被阻止的工具调用尝试与审计相关,并且不会出现在 trace 瀑布图中。只查询 traces 数据流会遗漏这类事件。

对于聚合视图,有一个托管仪表板,可以从同一个设置面板中按每个 space 进行安装。

在覆盖这些运行的 15 分钟时间窗口内,它报告了 903,914 个输入 token、11,734 个输出 token 和 44 次 LLM 请求,其中有 35 个工具 spans,成功率为 100%,平均耗时为 0.42 秒。该仪表板由系统管理且为只读,因此如果要修改某个面板,需要复制一份;这样 Elastic 仍然可以继续改进原始仪表板。

OpenTelemetry LLM traces 默认不会捕获哪些内容

默认情况下,trace 记录的是结构和成本,而不是内容。Advanced privacy settings 下有六个开关,用于控制提示词、响应、工具调用详情、系统提示词、真实的工具和 agent 名称,以及真实的对话和工作流 ID;这六个开关默认全部关闭。

默认情况下,trace 记录的是结构和成本,而不是内容。在瀑布图中选择任意 span,详情面板会直接显示:"此 span 没有可用的输入/输出数据。"

标识符会经过哈希处理,而不是直接丢弃。包含被阻止工具调用的那次运行通过 API 返回了 conversation be30fb53-d351-4fa1-b5e1-a569816f85d9,但其 spans 携带的是 gen_ai.conversation.id: b1141340d0851a46。这样你可以将属于同一个 conversation 的所有 spans 分组,并在不同 conversation 之间进行比较,同时不会暴露能够追溯到用户会话的标识符。

因此,除非启用真实 ID,否则你无法通过 conversation ID 将 traces 与 conversations 进行关联,而通常也没有这个必要。converse API 会直接提供关联键:

bash 复制代码
`

1.  {
2.    "conversation_id": "be30fb53-d351-4fa1-b5e1-a569816f85d9",
3.    "trace_id": "3f8b9722dbd371ac4b7ad75e4bed13b6",
4.    "model_usage": {
5.      "llm_calls": 22,
6.      "input_tokens": 518251,
7.      "output_tokens": 6423,
8.      "model": "anthropic-claude-4.6-sonnet"
9.    }
10.  }

`Lobster AI![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

将这个 trace_id 存储在你自己的决策记录中,这样无需削弱默认的隐私保护设置即可完成关联。只有在确实需要将具体响应精确归因到决策时,才启用真实 ID,并在进行相同更改时限制 trace 索引的访问权限。

在 trace 之外审计 AI agent 操作

traces 只记录 agent 做了什么,因此,显示谁授权了该操作的记录必须来自其他地方。

AI agent 操作使用谁的权限运行?

agent 化管道涉及三种身份,每种身份都有自己的边界。

身份 运行时使用的权限 由什么决定 如何限制范围
Agent Builder 工具 使用当前聊天用户的权限 当前用户,因此两个人针对同一个问题可能获得不同的数据 通过 Agent Builder 权限中所述的角色进行限制
工作流步骤 所有 elasticsearch.*kibana.* 步骤共享一个存储的 API key 触发方式:手动运行使用启动运行的人员的身份,计划运行使用上次保存工作流的人员的身份 工作流授权
Trace 读取者 索引级访问权限,要么全部允许,要么全部拒绝 traces-agent_builder.otel-* 的角色授权 通过 trace 索引模式设置角色边界

在任何审查中,都需要考虑存储的 key 所带来的一个影响。停用用户或更改其角色不会刷新这个 key,工作流会继续使用它获取的权限运行,直到有人再次保存该工作流,或者将 Enabled 关闭后再重新打开。撤销某位工程师的访问权限本身并不会停止仍以该工程师身份运行的工作流。

将调查角色的权限范围限制为只读:

bash 复制代码
`

1.  POST /_security/role/agent-builder-observability-investigator
2.  {
3.    "cluster": ["monitor_inference"],
4.    "indices": [
5.      {
6.        "names": ["logs-*", "metrics-*", "traces-*"],
7.        "privileges": ["read", "view_index_metadata"]
8.      }
9.    ]
10.  }

`Lobster AI![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

读取 agent 自身的 traces 是单独的授权,需要对 traces-agent_builder.otel-* 具有 readview_index_metadata 权限。将这两个角色分开,因为负责调查故障事件的人员和负责审计 agent 的人员并不总是同一批人。

在 Elasticsearch 中记录谁批准了 agent 操作

运行工作流,它会在审批闸门处停止,此时审查人员看到的是渲染到请求中的 agent 结构化输出,而不是一个简单的确认提示。

执行记录非常详细。它会记录 resumedAtresumedBy、完整的 resumeInput 负载、每个步骤的 token 使用情况,以及指向自身的深层链接。

该执行历史是一个运营视图,而不是审计存储。底层的 .workflows-events 数据流专用于系统操作,并且会直接拒绝用户查询,因此你无法使用 ES|QL 跨越一个季度的决策进行查询,而且执行历史受保留策略控制,而不是受你的合规策略控制。

将决策写入一个由你控制的索引:

yaml 复制代码
`

1.  - name: review
2.    type: waitForInput
3.    with:
4.      message: |
5.        ## Approve the proposed checkout remediation?

7.        The evidence query matched {{ steps.collect_evidence.output.hits.total.value }} error events in the last hour.

9.        Agent classification: {{ steps.investigate.output.structured_output.incident_class }}
10.        Affected pod: {{ steps.investigate.output.structured_output.affected_pod }}
11.        Proposed action: {{ steps.investigate.output.structured_output.recommended_action }}
12.      schema:
13.        type: object
14.        properties:
15.          decision:
16.            type: string
17.            enum: ["approve", "decline"]
18.          reason:
19.            type: string
20.            enum: ["supported-by-evidence", "insufficient-evidence", "wrong-target", "unsafe-action"]
21.          notes:
22.            type: string
23.        required: ["decision", "reason"]

25.  - name: record_decision
26.    type: elasticsearch.index
27.    with:
28.      index: "agent-action-audit"
29.      document:
30.        "@timestamp": "{{ now | date: '%Y-%m-%dT%H:%M:%S.%LZ' }}"
31.        "event.action": "agent_recommendation_reviewed"
32.        "incident.id": "{{ consts.incident_id }}"
33.        "agent.conversation_id": "{{ steps.investigate.output.conversation_id }}"
34.        "agent.incident_class": "{{ steps.investigate.output.structured_output.incident_class }}"
35.        "agent.affected_pod": "{{ steps.investigate.output.structured_output.affected_pod }}"
36.        "agent.recommended_action": "{{ steps.investigate.output.structured_output.recommended_action }}"
37.        "agent.evidence_count": "{{ steps.collect_evidence.output.hits.total.value }}"
38.        "review.decision": "{{ steps.review.output.response.decision }}"
39.        "review.reason": "{{ steps.review.output.response.reason }}"
40.        "review.notes": "{{ steps.review.output.response.notes }}"
41.        "review.responded_by": "{{ steps.review.output.respondedBy }}"
42.        "workflow.execution_id": "{{ execution.id }}"
43.        "workflow.executed_by": "{{ execution.executedBy }}"
44.        "workflow.execution_url": "{{ execution.url }}"

`Lobster AI![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

上面的工作流代码片段中有两个细节与参考页面不同。

审查人员负载多嵌套了一层。文档描述的是 steps.<name>.output.<field>,但正在运行的构建版本会将提交的值放在 response 下,同时还有一个 respondedBy 字段:

json 复制代码
`

1.  {
2.    "response": { "decision": "approve", "reason": "supported-by-evidence" },
3.    "respondedBy": "1506416774"
4.  }

`Lobster AI

execution.executedBy 记录谁启动了运行,而 respondedBy 记录谁批准了操作。在人工参与的管道中,这两者通常是不同的人。

第二个细节是时间戳。{{ now }} 会渲染为类似 Sun Jul 26 2026 07:37:11 GMT+0000 (Coordinated Universal Time) 的 JavaScript 日期字符串,而 Elasticsearch 会拒绝这种格式,并返回 failed to parse date fieldexecution.startedAt 也存在同样的问题。Liquid 的 date 筛选器可以解决这个问题。

工作流编辑器还会在首次运行之前将 steps.review.output.* 标记为无效变量,因为只有在有人作出响应后,审查人员负载的结构才会确定。该警告会在步骤获得实际输出后消失,并且模板会在运行时正确解析。

创建仅允许追加的数据流

如果审计追踪可以被 agent 自己的管道重写,那么它就不能算是真正的审计追踪。Elasticsearch 提供了两个相互独立的控制机制,并且可以组合使用。

首先,将数据写入数据流,而不是索引,因为数据流只接受追加操作,不接受其他操作:

bash 复制代码
`

1.  PUT _index_template/agent-action-audit
2.  {
3.    "index_patterns": ["agent-action-audit"],
4.    "data_stream": {},
5.    "priority": 500,
6.    "template": {
7.      "mappings": {
8.        "properties": {
9.          "@timestamp":            { "type": "date" },
10.          "event.action":          { "type": "keyword" },
11.          "incident.id":           { "type": "keyword" },
12.          "agent.conversation_id": { "type": "keyword" },
13.          "agent.evidence_count":  { "type": "long" },
14.          "agent.recommended_action": { "type": "keyword" },
15.          "review.decision":       { "type": "keyword" },
16.          "review.reason":         { "type": "keyword" },
17.          "review.responded_by":   { "type": "keyword" },
18.          "workflow.execution_id": { "type": "keyword" }
19.        }
20.      }
21.    }
22.  }

`Lobster AI![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

其次,只授予写入者 create_doc 权限,不授予其他任何权限,这样它可以添加记录,但无法使用按查询操作等绕过限制的方式:

bash 复制代码
`

1.  PUT _security/role/agent-action-audit-writer
2.  {
3.    "indices": [
4.      { "names": ["agent-action-audit"], "privileges": ["create_doc", "auto_configure"] }
5.    ]
6.  }

`Lobster AI

在正在运行的集群上进行测试后,这两个控制机制的行为符合审计存储的要求:

以审计写入者身份执行的操作 结果
追加一条决策记录 201 Created
按 ID 覆盖一条记录 400,数据流中只允许使用 op_type: create
使用 _update_by_query 修改一条决策 403,操作未获授权
使用 _delete_by_query 删除历史记录 403,操作未获授权
使用 _search 读取审计记录 403,操作未获授权

最后一行的只写行为是有意设计的。写入决策的工作流没有理由读取这些决策,因此审计人员使用单独的读取角色,而写入者保持只写权限。

这两个控制机制的失败方式不同,这一点很重要。400 来自数据流本身,并且适用于所有人,包括超级用户。403 则来自角色权限,而超级用户仍然可以执行这些操作。因此,要实现防篡改的保留策略,就意味着需要将记录发送到 agent 操作人员无法管理的集群之外。

对于集群级别的活动,启用 Elasticsearch 和 Kibana 安全审计日志,并 将日志转发到监控部署。在 9.5 中,xpack.security.audit.enabled 成为了动态集群设置,因此 Elasticsearch 不再需要重启即可启用它,不过在编排部署中,仍然需要将日志发送到某个可读取的位置。

使用 ES|QL 查询决策追踪

工作流运行两次,一次批准,一次拒绝,会产生两行记录,你可以将它们与 Elastic 中的其他数据一起进行查询。

sql 复制代码
`

1.  FROM agent-action-audit
2.  | KEEP @timestamp, agent.incident_class, agent.affected_pod, agent.recommended_action,
3.         agent.evidence_count, review.decision, review.reason, review.responded_by,
4.         workflow.execution_id
5.  | SORT @timestamp DESC

`Lobster AI

两次运行都看到了相同的 90 个错误事件,并且都针对 checkout-worker-1 提议执行 restart-checkout-worker。第一次审查以 supported-by-evidence 为理由批准了该操作,第二次则以 wrong-target 为理由拒绝,理由是重启 pod 只是掩盖定价数据源问题,而不是解决问题。

由于两次决策都是结构化字段,因此审查意见之间的分歧也是可以查询的。你可以统计每个故障事件类别的拒绝次数,并按照原因进行分组:insufficient-evidence 会将你引导回调查路径,而 unsafe-action 则会将你引导到工作流及其权限边界。

需要针对这些 AI agent 可观测性限制进行设计

有四种行为值得在设计时加以考虑,而且在编写工作流之前处理这些问题的成本更低。

  1. Trace 访问权限是索引级别的,而不是按用户划分的 。包含敏感对话的 space 需要在 traces-agent_builder.otel-* 上设置角色边界,而不是通过 UI 设置。

  2. 托管仪表板不会在新 space 中自动安装。将其添加到 space 配置清单中。

  3. 工作流执行具有自己的 APM traceId 。它与 Agent Builder 的 ai.agent 步骤生成的 spans 所使用的 trace 并不是同一个 trace,因此应该通过 conversation ID 或 agent 返回的 trace_id 进行关联,而不是期望一个 trace 覆盖两者。

  4. waitForInput 的输出结构与参考页面不同 。提交的值会放在 response 下,同时还有 respondedBy,如上所述。

这些问题都不会阻碍这种模式。

从哪里开始使用 AI agent 可观测性

开启 trace 收集,在 agent 运行所在的 space 中安装仪表板,然后打开一次真实 conversation 的瀑布图。它会展示工具调用顺序、模型分配以及延迟分布,而这些信息无法从回答文本中获得。

然后选择一个你已经信任其运行手册的单一故障事件类别,并在其审批闸门之后添加一个 elasticsearch.index 步骤。一个仅允许追加的决策记录只需要一个工作流步骤,却可以回答审查所需的三个问题:谁批准了这个操作、依据什么证据批准,以及之后发生了什么。

有关详细信息,请参阅收集 Agent Builder tracestraces 概览仪表板Agent Builder 权限工作流授权以及 waitForInput 参考文档

常见问题

Agent Builder trace 收集默认开启吗?

是的,在 9.5 和 Serverless 中默认开启。它会写入 traces-agent_builder.otel-<space-id>,无需配置 collector。

Traces 包含提示词和模型响应吗?

不包含。六个隐私开关分别控制提示词、响应、工具调用详情、系统提示词、真实的工具和 agent 名称,以及真实的 conversation 和工作流 ID,并且这六个开关默认全部关闭。

我可以限制谁能够读取 agent traces 吗?

只能在索引级别进行限制,通过角色控制对 traces-agent_builder.otel-* 的访问。访问权限不会按用户或 conversation 进行限制。

Traces 仪表板会自动安装吗?

不会。需要从 GenAI Settings 中的 Agent Builder Traces 部分为每个 Kibana space 安装一次。

为什么要单独写入决策索引,而不是使用工作流执行历史?

.workflows-events 专用于系统操作,并且会拒绝用户查询;此外,执行历史遵循自身的保留策略,而不是你的合规策略。

原文:Your AI agent needs an alibi: Observability & audit trails for Agent Builder in Elastic | Elastic Observability Labs

相关推荐
Elasticsearch7 小时前
仪表板活动日志:了解哪些 Kibana 仪表板会被使用
elasticsearch
Elasticsearch1 天前
从 22.61GB 到 15.63GB:Elasticsearch 9.5 如何用「混合存储」重新定义日志数据库
elasticsearch
Elasticsearch1 天前
用于自托管 LLM 调优的 vLLM Prometheus 指标:TTFT、KV Cache 和 GPU 利用率
elasticsearch
Sayai1 天前
Elasticsearch 快照备份到 NAS(NFS)实战:SLM 自动化 + 365 天保留策略
elasticsearch·自动化·jenkins
JavaPub-rodert2 天前
写软著 - Copyright Forge Skill 完整闭环改造方案
大数据·elasticsearch·搜索引擎
Elastic 中国社区官方博客2 天前
从建议到修复的 4 个阶段:使用 Elastic Workflows 实现人在回路中的自动化
运维·数据库·人工智能·后端·elasticsearch·ai·自动化
Elasticsearch2 天前
使用 OpenTelemetry 进行 Android 应用监控:从点击到后端的分布式追踪
elasticsearch
Elasticsearch2 天前
安心睡过凌晨 3 点的告警:在 Red Hat OpenShift 上使用 Elastic 实现自动化故障事件响应
elasticsearch
Elasticsearch3 天前
将 1,100 个文件迁移到 Redux Toolkit v2,同时避免冻结 Kibana 单体仓库
elasticsearch