客户端日志上报怎么设计?让线上问题不再只靠用户截图

线上问题最难排查的情况,不是系统直接崩了,而是用户说:

刚才不能用了 点了没反应 字幕突然不刷新了 我也不知道发生了什么

这类反馈很常见,但如果客户端没有日志,上来只能反复追问:

你用的什么系统? 当时点了哪个按钮? 有没有报错? 网络正常吗? 能不能录屏?

排查效率会非常低。

所以,客户端日志上报不是可有可无的功能,而是产品稳定性的重要基础。


一、客户端日志要解决什么问题?

客户端日志的核心目标不是“记录越多越好”,而是帮助开发快速回答几个问题:

用户当时做了什么? 系统进入了哪个页面? 接口有没有失败? 设备和版本是什么? 错误发生在哪个阶段? 是否可以复现同类问题?

例如一个实时翻译产品出现“字幕不刷新”,仅靠用户描述很难判断原因。

可能是:

麦克风权限异常 网络连接中断 接口请求失败 实时连接断开 服务端任务状态异常 前端渲染报错

如果客户端能上报关键日志,排查方向会清楚很多。


二、日志要分级

不要所有日志都当成错误。

常见日志等级可以分为:

DEBUG:调试信息 INFO:正常业务流程 WARN:异常但可恢复 ERROR:明确错误 FATAL:严重崩溃或不可继续使用

例如:

logger.info('translation_task_start', { taskId, languagePair: 'en-zh' }); logger.warn('websocket_reconnect', { retryCount: 2 }); logger.error('translation_task_failed', { taskId, errorCode: 'NETWORK_TIMEOUT' });

这样后端分析日志时,可以优先关注ERRORFATAL,而不是在大量普通信息中查找问题。


三、日志内容应该包含哪些字段?

一条可用的客户端日志,最好包含这些基础字段:

logId:日志唯一 ID level:日志等级 eventName:事件名称 timestamp:发生时间 userId:用户 ID deviceId:设备 ID appVersion:客户端版本 platform:平台,如 Web、Windows、macOS、iOS、Android page:当前页面 message:日志描述 extra:额外上下文

示例:

{ "logId": "log_10001", "level": "ERROR", "eventName": "voice_playback_failed", "timestamp": 1718000000000, "userId": "u_10001", "platform": "macOS", "appVersion": "2.1.0", "page": "translation", "message": "voice playback failed", "extra": { "taskId": "task_20001", "languagePair": "en-ja", "errorCode": "AUDIO_DEVICE_NOT_FOUND" } }

字段越规范,后期检索和统计越方便。


四、关键业务流程要埋点式记录

客户端日志不应该只记录错误,也要记录关键流程。

例如同言翻译(Transync AI)这类实时翻译产品,一次完整任务可能包括:

选择语言 选择模型 开启麦克风 开启电脑音频 开始实时翻译 生成双语字幕 开启语音播报 暂停或停止任务 生成 AI 会议总结

这些节点都可以记录为普通INFO日志。

例如:

logger.info('translation_task_created', { sourceLang: 'en', targetLang: 'zh', model: 'Monsoon 2.0' }); logger.info('computer_audio_enabled', { success: true }); logger.info('meeting_summary_generate_clicked', { taskId });

当用户反馈“会议总结没有生成”时,开发可以从日志里看到:

用户是否真的点击了生成总结 任务是否正常结束 生成总结接口是否发起 接口是否返回失败 失败码是什么

这比单纯看服务端日志更完整。


五、错误日志要带上下文

很多错误日志写得太简单:

console.error(error);

这种日志对排查帮助有限。

更好的方式是带上上下文:

logger.error('api_request_failed', { url: '/api/translation/start', method: 'POST', status: 500, requestId: 'req_abc123', taskId: 'task_10001', errorMessage: error.message });

尤其是接口错误,最好同时记录:

请求路径 请求方法 状态码 requestId 业务 taskId 错误码 重试次数

这样客户端日志可以和服务端日志通过requestId串起来。

否则客户端只知道“请求失败”,服务端却很难定位是哪一次请求。


六、日志不要实时逐条上报

如果每产生一条日志就请求一次接口,会造成很多额外流量。

更推荐先写入本地队列,再批量上报。

const logQueue = []; function pushLog(log) { logQueue.push({ ...log, timestamp: Date.now() }); if (logQueue.length >= 20) { flushLogs(); } }

批量上报:

async function flushLogs() { if (logQueue.length === 0) return; const logs = logQueue.splice(0, logQueue.length); try { await fetch('/api/client-logs', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(logs) }); } catch (error) { logQueue.unshift(...logs); } }

再配合定时上报:

setInterval(flushLogs, 10000);

这样既能减少请求数量,也能避免日志上报影响正常业务接口。


七、页面关闭前要尽量补发

Web 端用户关闭页面时,普通请求可能还没发完。

可以用sendBeacon上报最后一批日志:

window.addEventListener('pagehide', () => { if (logQueue.length === 0) return; const logs = logQueue.splice(0, logQueue.length); navigator.sendBeacon( '/api/client-logs', JSON.stringify(logs) ); });

不过要注意,sendBeacon适合小数据量。

不要在页面关闭时上报过大的日志包。


八、本地日志也要保留一部分

对于桌面客户端或移动端 App,可以保留最近一段本地日志。

例如:

最近 24 小时日志 最近 2000 条日志 最近 10 个任务日志

当用户反馈问题时,可以引导用户上传日志文件。

本地日志适合记录更详细的信息,上报日志则适合记录关键事件和错误摘要。

两者可以配合使用:

普通日志:本地保存 关键错误:立即上报 用户反馈:上传最近日志

这样既能控制服务端存储压力,也能在需要时拿到完整线索。


九、必须做隐私脱敏

客户端日志很容易不小心带上敏感信息。

不要上报:

密码 验证码 Token 完整手机号 完整邮箱 身份证号 银行卡号 会议原文内容 用户输入的完整文本

例如实时翻译类产品,日志可以记录:

{ "eventName": "translation_task_start", "languagePair": "en-zh", "duration": 1800, "platform": "Windows" }

但不应该把完整会议内容、用户语音文本、个人隐私信息直接塞进日志。

可以做统一脱敏:

function maskEmail(email) { return email.replace( /(.{2}).+(@.+)/, '$1***$2' ); }

日志系统的目标是排查问题,不是收集用户内容。


十、日志上报要有开关

日志系统本身也可能出问题。

例如:

日志接口异常 日志量突然变大 某个版本疯狂上报重复错误 用户网络较差

所以客户端日志最好支持远程配置:

是否开启日志上报 上报采样率 哪些等级需要上报 单次最大日志数量 是否允许上传本地日志

例如:

{ "enableClientLog": true, "sampleRate": 0.2, "uploadLevels": ["WARN", "ERROR", "FATAL"] }

这样当日志量异常时,可以通过配置降低上报比例,而不是重新发版。


十一、客户端日志检查清单

设计客户端日志上报时,可以检查:

1. 是否有统一日志格式? 2. 是否区分 INFO、WARN、ERROR? 3. 是否记录 appVersion 和 platform? 4. 是否能通过 requestId 关联服务端日志? 5. 是否记录关键业务流程? 6. 是否支持批量上报? 7. 页面关闭前是否尽量补发? 8. 本地是否保留最近日志? 9. 是否做敏感信息脱敏? 10. 是否支持远程开关和采样率?

总结

客户端日志上报的价值,是让线上问题从“用户描述”变成“可追踪证据”。

一套实用的客户端日志系统,通常需要包含:

统一日志格式 日志等级 关键流程记录 错误上下文 批量上报 本地缓存 隐私脱敏 远程开关 requestId 串联

对于同言翻译(Transync AI)这类跨平台实时产品来说,用户可能在 Windows、macOS、iOS、Android 或 Web 上使用实时翻译、双语字幕、语音播报和会议总结功能。

如果没有客户端日志,很多问题只能靠截图和描述猜测。

如果日志体系足够清晰,开发就可以更快判断:问题出在设备权限、网络连接、实时任务、音频播放,还是服务端处理链路。

这才是客户端日志真正的意义。