ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PostHog Endpoint 执行日志排查指南:读懂 log_entries 中每次运行的真相

PostHog Endpoint 执行日志排查指南:读懂 log_entries 中每次运行的真相 PostHog Endpoint 执行日志排查指南读懂 log_entries 中每次运行的真相【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog端点Endpoint是 PostHog 将保存的 HogQL 或 Insight 查询暴露为可调用 API 路由的能力。每一次端点调用都会在log_entries存储中留下一条执行日志。本文以 exploring-endpoint-execution-logs/SKILL.md 为主体结合仓库中的日志发射实现、执行逻辑与测试用例系统讲解如何通过执行日志回答端点运行时到底发生了什么——是报错、缓存未命中、慢查询还是返回行数异常。读完本文你将掌握执行日志的格式语义、endpoint-logs工具的过滤技巧、跨多次运行的聚合分析方法以及一套可复用的排查工作流。一、什么是端点执行日志用途与适用边界PostHog 的每个端点Endpoint执行一次就会向log_entries存储写入一条执行日志条目。这条日志回答的问题是What happened when it ran?即这次运行时发生了什么。何时使用本技能当出现以下类型的诉求时应使用执行日志排查我的端点为什么报错 / 失败给我看端点 X 的日志 / 最近几次运行上次运行命中缓存了吗返回了多少行端点 Y 上一次运行时发生了什么何时不该用执行日志技能文档明确划定了边界如果问题本质是端点太慢了我该改什么应转向diagnosing-endpoint-performance技能该技能从配置与query_log的代价指标出发推理缓存/物化策略见 diagnosing-endpoint-performance/SKILL.md如果问题横跨整个项目有什么可以清理的则属于auditing-endpoints的范畴见 auditing-endpoints/SKILL.md。执行日志聚焦单个具名端点的运行时记录不做项目级审计也不做查询性能剖析。二、一条执行日志长什么样格式与 Token 语义每次运行恰好产生一条日志条目成功时 level 为INFO失败时 level 为ERROR。消息体中携带的附加数据以可搜索的keyvaluetoken 形式存在Endpoint executed · pathmaterialized cachehit duration_ms142 rows1024 version3 Endpoint execution failed · pathinline errorResolutionError version3Token 含义对照表Token取值含义pathmaterialized/inline/ducklake/ducklake_fallback本次运行走的是哪条执行路径cachehit/miss查询结果缓存是否命中ducklake 路径省略该 tokenduration_ms整数墙钟执行耗时毫秒rows整数返回的结果行数version整数运行的是端点的哪个版本error如ResolutionError、HogVMException错误类 / HogQL 代码名仅在失败时出现每次运行都有独立的instance_id因此在日志查看器中日志按每次执行一条进行分组。源码级佐证token 是如何拼出来的日志消息由 products/endpoints/backend/logs.py 中的build_execution_messageL18-L43构建prefix Endpoint executed if succeeded else Endpoint execution failed tokens { path: execution_type, cache: cache_outcome, duration_ms: duration_ms, rows: rows, version: version, error: error, } token_str .join(f{key}{value} for key, value in tokens.items() if value is not None) return f{prefix} · {token_str} if token_str else prefix两点值得注意token 是稀疏的值为None的 token 会被直接剔除所以成功日志没有errorducklake 路径没有cache失败日志通常也没有duration_ms/rows。刻意不记录变量值函数 docstring 明确说明Only non-sensitive execution metadata belongs here. Never add variable values——they routinely carry PII。也就是说日志中永远不会出现邮箱、客户 ID、过滤条件等变量取值这是防止 PII 泄漏的设计底线。在 products/endpoints/backend/logic/execution.py 的execute顶层入口L500 起中成功路径在 L680-L693 发射INFO日志携带cache_outcome、rows、duration_ms、version失败路径在 L665-L677 发射ERROR日志携带errorerror_label。错误标签来自 L608-L654 的异常分类ResolutionError无法解析表或字段引用、HogVMExceptionHogQL 虚拟机错误、ExposedHogQLError/ExposedCHQueryError取code_name、查询超预算、并发受限等各自对应一个可搜索的error取值。从源码结构看path的实际取值由执行路径选择逻辑产生L555、L604默认取materialized或inline当物化表执行失败、回退到内联执行成功时会标记为materialized_fallback。而ducklake相关路径源于 DuckLake 影子执行机制L460-L494只有内联执行且未命中缓存的运行才会触发与 DuckLake 的耗时对比影子查询受endpoints-ducklake-shadow-execution特性开关控制且影子查询永远不影响真实响应。三、日志是怎么落库的best-effort 发射机制log_endpoint_executionlogs.py L46-L74负责真正把日志写入log_entriesproducer get_producer(topicKAFKA_LOG_ENTRIES) producer.produce( topicKAFKA_LOG_ENTRIES, data{ team_id: team_id, log_source: ENDPOINTS_LOG_SOURCE, log_source_id: str(endpoint_id), instance_id: instance_id, timestamp: datetime.now(tzUTC).strftime(_TIMESTAMP_FORMAT), level: level, message: message, }, )其中log_source固定为endpoints定义于 products/endpoints/backend/constants.py 的ENDPOINTS_LOG_SOURCEL37-L39日志页签与endpoints_logs_retrieveAPI 都按该值读取。log_source_id是端点 UUID不是端点名——这是后续用 SQL 聚合时最容易踩的坑。instance_id是本次执行的唯一 ID。关键在于best-effort 语义整个发射过程被try/except包裹Kafka 生产失败只会 debug 级记录日志、绝不会中断或拖慢端点运行也不做 flushproduce()非阻塞轮询。因此调用方成功但日志里看不到这条运行是完全可能发生的——是日志被丢弃了而不是查询没执行。测试用例test_produce_failure_is_swallowed专门验证了 Kafka 挂掉时日志发射不会抛异常。响应中的 execution_id 与日志 instance_id 一一对应执行开始时execute会生成execution_id str(uuid.uuid4())L558并把它与endpoint_version一起写进成功响应体L707-L711result.data[name] endpoint.name result.data[execution_id] execution_id result.data[endpoint_version] version_obj.version而同一 ID 也作为instance_id写入日志。这意味着拿到任意一次调用的响应体里面的execution_id就是你在日志中按instance_id精确定位这条执行的钥匙。测试 test_successful_run_returns_execution_id_matching_log 断言了响应 ID 与日志instance_id必须相等正是为了保障这一可追踪性。四、可用工具一览工具用途endpoint-logs主工具。按名称读取单个端点的执行日志条目支持按 level、search、时间范围、instance_id 过滤limit上限 500。endpoint-get读取端点配置作为上下文当前版本、物化状态、查询类型。execute-sql兜底 / 聚合工具。直接对log_entries表执行 SQLlog_sourceendpoints。在 MCP 工具定义 products/endpoints/mcp/tools.yaml 中endpoint-logs对应 OpenAPI 操作endpoints_logs_retrievereadOnly且需要endpoint:read作用域L61-L77。其描述对 token 语义做了同样说明Each run emits one entry with a timestamp, level (INFO or ERROR), and a message whose extra data is in keyvalue tokens (pathmaterialized|inline|ducklake, cachehit|miss, duration_ms, rows, version, error)可用于调试端点为何失败、超时、缓存未命中或返回了意外行数。后端层面端点日志由 EndpointViewSet 通过LogEntryMixin提供log_source ENDPOINTS_LOG_SOURCElogs被列为只读 action且lookup_field name即按名称而非 UUID 访问端点及其日志。底层的查询逻辑在 posthog/api/log_entries.py 的LogEntryMixinL132 起按log_source、log_source_id、可选的instance_id构造 WHERE 条件ORDER BY timestamp DESC并对 level 做upper(level)规范化输出。五、过滤条件详解endpoint-logs暴露了标准的日志过滤项level— 逗号分隔。例如只填ERROR只看失败运行填INFO,ERROR则全部查看。search— 对消息做大小写不敏感的子串匹配。由于附加数据是keyvaluetoken你可以直接搜索cachemiss、pathinline、errorResolutionError或某个具体的version3。after / before— ISO 时间戳用于限定时间范围。instance_id— 锁定单次执行配合响应体中的execution_id使用。limit— 取值范围 1–500默认 50。这些过滤在 API 层有对应校验test_logs_action_filters_by_level 验证了levelERROR只返回 ERROR 条目test_logs_action_rejects_invalid_limit 验证了limit999会被拒绝400。同时日志严格按团队隔离test_logs_action_isolated_across_teams 表明无法从本团队上下文访问其他团队端点的日志返回 404。六、排查工作流五步法按名称锁定端点。如果用户给的是 URL从/api/projects/{team_id}/endpoints/{name}/run中解析出name。先宽后窄对端点执行endpoint-logs时间范围取最近一段时间先通览 level 与 token 分布。聚焦症状失败 →levelERROR读errortoken 和pathtoken 判断在哪里断的。缓存问题 →searchcachemiss看运行错过缓存的频率。结果错误 → 对比多次运行的rows并用version定位版本升级后是否出现回归。跨多次运行做计数/趋势例如统计一周内的错误率降级到execute-sql直接对log_entries聚合SELECT toDate(timestamp) AS day, upper(level) AS level, count() AS runs FROM log_entries WHERE log_source endpoints AND log_source_id endpoint_uuid GROUP BY day, level ORDER BY day DESC注意log_source_id是端点 UUID 而非名称——先通过endpoint-get拿到它。给出结论说明什么在失败、从何时开始、发生在哪个版本/路径上并判断是配置问题移交给diagnosing-endpoint-performance还是查询 bug。七、完整示例交互User: weekly_signups started erroring this morning Agent steps: - endpoint-logs weekly_signups, levelERROR, afterthis morning → several Endpoint execution failed · pathinline errorResolutionError version5 - endpoint-get weekly_signups → current version is v5 (bumped today) - endpoint-logs weekly_signups, levelINFO, beforethis morning → prior runs: pathinline cachehit ... version4 succeeded - v5 (created this morning) is failing with a ResolutionError on the inline path — it cant resolve a table or field reference. v4 ran fine. This looks like a bad query in the new version. Want me to pull the v5 query (endpoint-versions) so we can fix it, or roll back to v4?这个例子展示了排查的核心逻辑闭环用versiontoken 把故障与版本发布事件关联起来——先确认故障集中在 v5再确认 v4 历史运行正常从而把怀疑范围缩小到新版本的查询本身。修复或回滚的后续动作可参考 managing-endpoint-versions/SKILL.md。八、重要注意事项每次运行只有一条日志。不要期待分步骤的 trace——端点只记录一行完成态日志细节都在 token 里而不是在多行日志中。log_source_id是端点 UUID不是名称。使用execute-sql前必须先通过endpoint-get获取。日志保留约 90 天log_entries的 TTL更早的运行不会出现。执行日志 ≠ 查询性能。endpoint-logs告诉你发生了什么、为什么失败对于该不该物化 / 要不要调大缓存 TTL这类问题应使用diagnosing-endpoint-performance它基于配置与query_log代价指标推理。日志是 best-effort 发射。日志行在每次运行后发射但从不阻塞运行——如果调用方已成功而日志缺失说明日志发射被丢弃而不是查询失败。拒绝的请求也会留痕。execution.py 的log_rejected_run会把校验失败的请求如非物化端点使用direct刷新、缺少必需变量、非法 limit/offset、版本不存在以ERROR级别记成 Endpoint execution failed · invalid request · 所以连请求都没被接受同样能在日志中看到——相关行为由 test_invalid_refresh_mode_emits_error_log_and_clean_message 和 test_rejected_run_params_emit_error_log 验证且对外错误信息会剔除 pydantic 内部细节保证用户可见错误干净可读。九、数据流向小结从源码可以梳理出一条完整的日志链路用户调用/api/environments/{team_id}/endpoints/{name}/run/EndpointViewSet 按名称解析端点execution.py 的execute选择执行路径物化表 / 内联 / 物化回退生成execution_id并把执行结果与版本号一并写入响应体成功时以INFO、失败时以ERROR调用log_endpoint_execution消息由 build_execution_message 拼装为一行keyvaluetoken日志经 Kafka 进入log_entries表log_sourceendpoints、log_source_id端点 UUID、instance_idexecution_id由 LogEntryMixin 提供查询能力供endpoint-logs工具、日志页签与execute-sql消费整套发射是 best-effortKafka 故障时静默丢弃绝不阻塞查询本身。这条链路对应测试文件 test_endpoint_logs.py 覆盖的全部行为成功/失败日志内容、execution_id 与 instance_id 一致、请求校验拒绝也留痕、level 过滤、团队隔离与 limit 校验。理解这层实现后你在面对端点失败了时就能准确区分是查询 bug看error与version、是配置问题转交性能诊断技能、还是日志本身丢失best-effort 丢弃。【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表