可观测性后端【免费下载链接】highlighthighlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.项目地址https://gitcode.com/gh_mirrors/hi/highlight点击查看免费下载导读highlight.io 的Live Mode实时模式是 Session Replay 的一项核心能力它让开发者在用户仍停留在页面、仍在产生会话数据时就能以近乎实时的速度在回放查看器中观察用户的一举一动。本文以官方文档 live-mode.md 为主线结合仓库前端 Player 状态机、GraphQL 订阅机制与后端轮询实现完整讲清 Live Mode 的生效条件、数据可见性边界、时间轴行为以及如何在查看器中启用与退出实时模式帮助你真正用好这一排查线上问题的利器。一、Live Mode 是什么何时自动生效Live Mode 是 Session Replay 查看器的一种跟随最新的播放状态。根据官方文档的定义highlight.io supports tracking users in real-time as they use your web application. When you use highlight.ios Live Mode, the session viewer shows the latest data from users sessions.它是默认开启的且只对正在直播的会话生效——即用户仍然停留在页面上、并且持续向服务端发送会话数据时该会话在查看器中就处于 Live Mode一旦用户离开页面或会话数据停止上报会话便会退出直播状态转入普通的历史回放流程。从源码可以印证这一点查看器的控制栏只在特定条件下才渲染 Live Mode 开关。在 ToolbarControlBar.tsx 中有这样一行判断const showLiveToggle session?.processed false !disableControls也就是说只有当会话的processed字段为false会话尚未完成后端处理即用户仍在活跃/仍在写入事件时Live Mode 开关才会出现。已经处理完毕的历史会话不会进入 Live Mode这也与默认对 live 会话生效的文档描述完全一致。二、实时数据是如何流到查看器的GraphQL Subscription 增量轮询Live Mode 的技术核心是一条GraphQL Subscription订阅它把后端新写入的事件增量地推送给回放查看器。订阅协议的 Schema 定义订阅字段定义在 schema.graphqls 中type Subscription { session_payload_appended( session_secure_id: String! initial_events_count: Int! ): SessionPayload }它接收两个参数会话的session_secure_id以及initial_events_count——即前端已经拿到的事件数量后端从该游标位置开始增量返回后续事件。前端订阅与增量合入前端在 PlayerHook.tsx 中通过useEffect监听isLiveMode状态来建立/销毁订阅当state.isLiveMode为真且尚未建立订阅时调用subscribeToSessionPayload以sessionPayload.events.length作为initial_events_count注册OnSessionPayloadAppendedDocument每次收到推送通过updateQuery取出session_payload_appended.events把新事件追加进当前事件的 chunk再派发addLiveEventsaction同时记录last_user_interaction_time作为最后活跃时间当退出 Live Mode 时调用退订函数并暂停播放。unsubscribeSessionPayloadFn.current subscribeToSessionPayload({ document: OnSessionPayloadAppendedDocument, variables: { session_secure_id: sessionSecureId, initial_events_count: sessionPayload.events.length, }, updateQuery: (prev, { subscriptionData }) { const newEvents sd!.session_payload_appended.events! if (newEvents.length) { const events [...getEvents(chunkEventsRef.current), ...toHighlightEvents(newEvents)] chunkEventsSet(0, events) dispatch({ type: PlayerActionType.addLiveEvents, firstNewTimestamp: toHighlightEvents(newEvents)[0].timestamp, lastActiveTimestamp: new Date( subscriptionData.data!.session_payload_appended.last_user_interaction_time, ).getTime(), }) } return prev }, })后端轮询实现后端的 resolver 位于 schema.resolvers.go。它以initialEventsCount构造一个model.EventsCursor然后进入一个每秒轮询一次的循环每次调用getEvents获取从当前游标开始的增量事件若len(events) ! 0就通过 channel 推送出去并把游标前移。这保证了前端始终能看到最新写入的会话事件。需要特别注意的是这段后端代码中的一行注释// TODO live updating for other event types它揭示了一个重要事实当前 Live Mode 的实时推送只覆盖了 replay 事件流rrweb 录制的事件而 Errors、RageClicks、SessionComments 这三个字段在推送时被显式置为空数组。这与文档中的描述互相印证——实时模式下部分数据并不可见详见下一节。三、Live Mode 的数据可见性边界哪些能看到哪些看不到这是使用 Live Mode 时最容易产生困惑的一点。官方文档明确指出While you can view how a session looks to a user in real time, note that some events havent been processed and will not be visible. Errors, console logs, and network traffic will only be visible when Live Mode is disabled, up to whats most recently processed.翻译成可操作的结论就是数据类型Live Mode 下是否可见说明屏幕画面 / 用户操作rrweb 事件流✅ 可见通过session_payload_appended订阅实时推送Errors错误❌ 不可见后端推送的Errors字段为空数组Console logs控制台日志❌ 不可见需退出 Live Mode 后按最新已处理数据加载Network traffic网络请求❌ 不可见同上这些数据的可见性受后端处理管线异步清洗、索引、关联错误组等进度影响它们只有在已处理完成之后才会出现在查看器中。因此文档建议如果需要查看某次会话的报错、控制台日志或网络请求应当退出 Live Mode此时查看器会回退到最近一次已处理完成的数据进行展示。对应的代码佐证在 schema.resolvers.go推送的SessionPayload中ch - model.SessionPayload{ Events: events, Errors: []model.ErrorObject{}, // 实时推送时为空 RageClicks: []model.RageClickEvent{}, // 实时推送时为空 SessionComments: []model.SessionComment{}, // 实时推送时为空 LastUserInteractionTime: session.LastUserInteractionTime, }四、时间轴行为Live Mode 下为什么不能拖动进度条在普通回放模式中你可以拖动进度条、逐帧回放、调整播放速度但在 Live Mode 下这些操作是受限的。文档的解释是In Live Mode, time-scrubbing is disabled since youre always seeing the latest session view.原因在于 Live Mode 的语义是永远跟随最新播放器的时间位置会被不断追加的事件推着前进而不是由你手动定位。前端的 Player 状态机在收到addLiveEventsaction 时会执行PlayerState.tscase PlayerActionType.addLiveEvents: s.liveEventCount 1 s.lastActiveTimestamp action.lastActiveTimestamp s.replayer?.replaceEvents(getNonCustomEvents(events)) s.replayer?.play(events[events.length - 1].timestamp) s.replayerState ReplayerState.Playing break即用最新的事件列表替换播放器事件、并直接play到最后一个事件的时间戳——播放器始终被钉在实时的最前沿。这就是为什么在实时模式下时间轴拖拽没有意义因为下一个事件推送过来播放位置又会自动跳走。与此同时状态机还维护了一个liveEventCount计数器其注释写道PlayerState.ts// Incremented whenever events are received in live mode. This is subscribed // to for knowing when new live events are available to add to the player. liveEventCount: number它用于让 UI 感知又有新实时事件到达从而触发播放器的增量合入。此外从状态机的其他分支也能看到 Live Mode 与播放控制的联动暂停即退出实时PlayerActionType.pause分支会先把s.isLiveMode false再暂停PlayerState.ts因为实时模式下播放器本来就不该被暂停在某个旧位置加载新会话时重置loadSession与reset分支都会将isLiveMode重置为falsePlayerState.ts回放相关功能被禁用控制栏中的播放速度调整、时间/进度显示、Histogram 时间直方图开关、Skip Inactive 跳过无操作区间开关等都只在!isLiveMode时才渲染或可用见 ToolbarControlBar.tsx。五、如何启用 / 退出 Live Mode开关按钮与评论的自动退出1. 手动切换开关查看器控制栏中有一个显式的 Live Mode 切换按钮。其渲染逻辑与样式在 ToolbarControlBar.tsx{showLiveToggle ( Tag onClick{() { setIsLiveMode(!isLiveMode) }} shaperounded kind{isLiveMode ? primary : secondary} emphasis{isLiveMode ? high : medium} disabled{disableControls} lines1 {isLiveMode ? Disable : Enable} live mode /Tag )}按钮文案随状态切换为Disable live mode / Enable live mode开启时按钮以 primary/high 高亮显示关闭时为 secondary/medium。关闭 Live Mode 后会发生什么文档明确指出You can always turn off Live Mode by clicking the toggle button, which will show the session up to the latest data processed.即退出实时模式后查看器会展示截至最近一次已处理数据的画面此时 Errors、console logs、network traffic 等已处理的关联数据也随之可见。从实现上看setIsLiveMode回调在退出时还会做一次补齐操作——先把当前已有的最新事件以addLiveEvents的方式追加给播放器再真正切换状态PlayerHook.tsx同时订阅退订、播放暂停PlayerHook.tsx。状态切换本身还会触发一条埋点事件analytics.track(Session live mode toggled, ...)PlayerState.ts。2. 在会话上写评论自动退出 Live Mode文档强调了一个容易忽略的行为Clicking on the session to write a comment will also disable Live Mode, since comments are associated with a particular timestamp.在实时模式下给会话打评论会自动关闭 Live Mode。这是因为评论必须锚定在某个具体的时间戳上——而实时模式下播放位置永远在变动时间轴拖拽又被禁用无法确定评论对应的画面时刻。因此系统强制先退出实时模式、回到可定位的历史时间轴再允许你选择时机写评论。六、实时模式下如何判断用户最后活跃时间进入 Live Mode 后控制栏会从时间/进度显示切换为Last activity最后活跃时间徽标ToolbarControlBar.tsx{isLiveMode lastActiveString ( Stack aligncenter directionrow gap4 Text sizexSmall colorweakLast activity/Text Badge iconStart{IconSolidClock size{12} /} label{lastActiveString} variantgray sizesmall / /Stack )}该时间来自后端推送的last_user_interaction_time见前文addLiveEvents对lastActiveTimestamp的赋值并最终反映到lastActiveString上。它告诉你用户最后一次与页面交互发生在何时是判断用户是否已离开或当前是否仍在活跃的重要信号。七、Live Mode 与其他 Session Replay 功能的关系Live Mode 属于 Session Replay 功能集 的一员与以下文档配合使用效果最佳dev-tools.md讲解 console logs、network requests、errors 的采集与展示理解这些数据为何在 Live Mode 下不可见、退出后如何按已处理数据呈现filtering-sessions.md用筛选条件快速定位正在直播的高价值会话再进入 Live Modeevents-and-users.md了解用户属性与事件追踪配合实时观察用户行为session-search.md通过检索直达某个活跃会话。八、最佳实践小结需要实时跟进某个疑似出问题的用户时在会话列表中定位processed false的会话进入后确认 Live Mode 已自动开启即可像看直播一样观察用户当前操作需要查看该会话的错误、控制台日志或网络请求时先点击 Disable live mode 退出实时模式让查看器回退到最新已处理的数据再配合 DevTools 面板分析发现用户最后活跃时间长时间不再更新说明用户很可能已离开页面或会话已结束此时可以退出 Live Mode 进入完整历史回放给会话写评论前系统会自动退出实时模式这是刻意设计——评论必须锚定在稳定时间戳上不必担心误操作。总结Live Mode 是 highlight.io 在 Session Replay 上实时性与完整性之间做权衡的产物它以 GraphQL Subscription 秒级增量轮询schema.resolvers.go保证画面实时跟随同时明确划定 Errors、Console、Network 等异步处理数据的可见性边界并用自动退出实时模式的设计保证评论锚点与时间轴拖拽的可用性。理解这些边界与状态机的联动逻辑PlayerState.ts你就能在排查线上问题时准确判断哪些数据可以实时看哪些必须退出 Live Mode 才能拿到。赞分享可观测性后端【免费下载链接】highlighthighlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.项目地址https://gitcode.com/gh_mirrors/hi/highlight点击查看免费下载相关推荐highlight.io 下的 Django 实时监控实战从原生日志配置到错误追踪与前后端会话关联highlight.io 下的 Django 实时监控实战从原生日志配置到错误追踪与前后端会话关联 本篇技术指南围绕 Django 应用实时监控的核心场景展开可观测性后端h3会话管理session实现原理h3会话管理session实现原理 还在为Web应用的用户状态管理头疼吗h3框架提供了简单高效的会话管理方案让你轻松实现用户状态持久化。本文将深入解析h3后端Web框架Agno Agent 会话分支Fork Session实战用 fork_session 实现非破坏性会话派生与血缘追踪Agno Agent 会话分支Fork Session实战用 fork_session 实现非破坏性会话派生与血缘追踪 会话级的分支能力让 Agent 可人工智能大模型AI AgentAgent 框架多智能体工具调用RAGAgent 工作流Agent 记忆上一篇PvZ Toolkit终极指南如何轻松掌控植物大战僵尸的游戏体验下一篇植物大战僵尸终极修改器PvZ Toolkit完整使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
MySQL 5.6绿色解压版Windows部署实战:配置、服务与避坑指南 简介:MySQL 5.6 绿色版压缩包,专为需要快速部署数据库的 Windows 用户打造,免去安装向导的繁琐步骤,解压即可投入使用,非常适合开发调试、临时数据库支撑等场景。资源整体为 zip 压缩包,大小仅 55.24MB&… · 2026/9/25 7:30:22
从免费CRM到自建客户管理系统:DeskcommCRM实战复盘与落地经验 做客户关系管理这件事,我前后折腾了好几年。DeskcommCRM 这个项目,就是我在踩了无数坑之后,自己动手搭出来的一套客户管理系统。如果你也是做销售团队管理的,或者手底下有一帮业务员天天在私聊里发客户名、在Excel表里填跟进记录&… · 2026/9/25 7:30:16
自建通讯型CRM系统实战:软电话与呼叫中心落地全解 DeskcommCRM 这个项目名拆开来看就是“桌面 通讯 客户关系管理”,说白了就是给每天坐在电脑前打电话、跟进客户的团队用的那套一体化工作平台。我最早接触这类系统是在一个做企业服务的电商代运营公司,几十个坐席每天靠 Excel 表格和手机打电话跟进客户… · 2026/9/25 7:30:16
深度拆解iMessage附件后门及辅助模块的完整分析链路 我最早接触“三角测量”(Triangulation)这个代号,是在处理一部iPhone异常发热、流量飙升的排查任务里。查了一整天日志,最后在一个不显眼的iMessage消息附件目录里翻出了一个伪装成图片的二进制文件,当时就觉得不对劲。… · 2026/9/25 7:54:22
酷狗KGG文件解密原理与六种实操方法详解 1. 这不是“破解”,而是对本地音频文件格式的合规技术解析酷狗音乐的.kgg和.kgm文件,本质上是经过封装加密的音频容器,不是传统意义上的“盗版保护”或“DRM版权锁”,而是一种客户端级的资源打包机制——它把原始音频(… · 2026/9/25 7:54:22
Atlas 300V 24G部署YOLO全流程:从推理加速卡到模型优化 1. 从热搜问题说起:Atlas 300V 24G到底是不是运算加速卡最近好几个群都在讨论Atlas 300V 24G,问的最多的就是“这玩意是不是运算加速卡”。我先直接给结论:是加速卡,但准确点说,它是AI推理加速卡,不是训练卡… · 2026/9/25 7:54:16
Atlas 300V 24G运算加速卡深度解析:从NPU原理到YOLO推理部署实战 项目群里又有人问起:“Atlas 300V 24G这卡到底算不算运算加速卡?是不是拿回来插上就能像显卡一样跑YOLO?”这个问题我太熟悉了,几乎每隔一段时间就会看到一次。坦白讲,我第一次拿到Atlas 300V Pro 24G的时候࿰… · 2026/9/25 7:54:16
SKILL.md 实战:用自然语言文档驱动 Agent 技能开发与 OpenClaw 落地 1. 从手搓 Agent 到 SKILL.md:一场开发范式的转移过去大半年,我几乎把市面上能见到的 Agent 框架都折腾了一遍。从最早的 ReAct 循环手写 prompt,到后来用各种编排框架搭工作流,再到接入 MCP 协议打通外部工具,每一步都… · 2026/9/25 7:54:16
大屏数据看板PPT模板改造:数据接入与避坑实战 简介:这份幻灯片模板专用于制作大屏可视化数据分析看板,面向产品运营、市场销售、财务分析等需要做数据汇报的职场人士,也适合中高层管理者用于经营复盘与项目展示,可快速生成清晰直观的大屏展示页面。压缩包内仅有一个演示文稿文… · 2026/9/25 7:54:15
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37