/** * logger.js — 结构化日志 * * 为什么单独成模块:设备脚本出错时,唯一能依赖的就是回传的日志。 * 把日志格式固定下来(`[TTA][步骤名] 内容`),PC 侧就能按前缀过滤、按步骤计时, * 而不是靠人肉读一堆散乱的 console.log。 * * 2026-10-13 增加**文件落盘通道**(sink):界面侧的「运行记录 → 详情的执行日志」 * 要看的就是这些行。之所以不做成"界面去抓 console",是因为 * console 是另一个进程的 stdout,界面根本读不到(见 bridge.js 的通道说明)。 * sink 由 bridge 在启用宿主模式时装上,**独立运行时为空 → 零开销**。 * * 依赖:无。始终通过 TikTokAuto.logger 取用,因此可以被放在 concat 顺序的最前面。 */ TikTokAuto.logger = (function () { 'use strict'; var PREFIX = '[TTA]'; var startedAt = Date.now(); /** 文件落盘回调,由 bridge 注入:function(level, step, message) */ var sink = null; function stamp() { return ('+' + (Date.now() - startedAt) + 'ms'); } function write(level, step, message) { var line = PREFIX + stamp() + '[' + level + '][' + step + '] ' + message; console.log(line); if (sink) { /* 落盘失败绝不能影响流程:日志是"顺带记录的",不是"必须成功的"。 */ try { sink(level, step, message); } catch (ignored) { /* 刻意吞掉:sink 抛错会把一次正常的日志调用变成流程中断 */ } } } return { /** 装上文件落盘通道(传 null 卸载) */ setSink: function (fn) { sink = typeof fn === 'function' ? fn : null; }, /** 记录一次进入某步骤 */ step: function (name, message) { write('STEP', name, message === undefined ? '' : message); }, info: function (step, message) { write('INFO', step, message); }, /** 可恢复的问题:值得记下来,但不中断流程 */ warn: function (step, message) { write('WARN', step, message); }, error: function (step, message) { write('ERROR', step, message); }, /** 机器可读的结构化结果,PC 侧用它做断言 */ result: function (payload) { console.log(PREFIX + 'RESULT ' + JSON.stringify(payload)); }, /** 从脚本开始到现在的耗时,用于定位"哪一步慢" */ elapsedMs: function () { return Date.now() - startedAt; } }; }());