1. 结论先行

本报告统计的是服务器上实际生成的日志文件大小,不是 Kibana message 字段长度,也不是 Elasticsearch 索引占用。

项目2026-08-262026-08-27变化归因结论
DGJ-AI,10.80.21.92/93约 38.00 GB约 46.11 GB+8.11 GB,+21.35%不能直接判定优化失效;27 号新增了 26 号未找到的日期日志文件,目录集合不一致
dgj-robot,10.80.22.21–26约 40.69 GB约 40.37 GB-0.31 GB,-0.77%本轮没有修改 Robot 网关代码,变化主要是流量和内容差异,不作为 dgj2.0 优化收益

AI 的可比同名大文件 robot-inquiry/kafka 从约 37.96 GB 降到约 37.46 GB,减少约 0.50 GB、1.32%。但 Kafka 入口代码本轮没有删除完整 payload,因此这一下降不能完全归因于代码优化。

本次代码优化的直接收益是:下游部分节点不再重复打印完整 message、notify、contact 和 preConversation;searchWxList 的返回值统一限制为最多 500 个字符。setContact:设置联系人 和当前 conversation 按保守策略仍保留完整对象,详见第 5 节。入口完整 Kafka 消息、格式错误原文和未知异常堆栈仍保留,保证可以按 RequestId、msg_id、sid 等字段排查。

2. 统计范围和口径

2.1 代码证据

  • 优化分支:bugfix/20260827-log。
  • 最新日志统一截断提交:801e22d706 日志优化。
  • 前一批链路去重提交:dd297f437f 日志精简修改。
  • 本机当前工作区在 feature/P1500,且存在与本报告无关的未提交改动;本报告没有修改当前工作区,代码证据直接读取 bugfix/20260827-log 引用。

2.2 服务器文件证据

  • AI:10.80.21.92、10.80.21.93,目录 /data/logs/dgj。
  • Robot:10.80.22.21–10.80.22.26,目录 /data/logs/inner-robot。
  • 26 号和 27 号均按文件名明确带日期的日志统计。
  • 精确值使用文件字节数汇总;截图中的 du -sh 会按文件系统单位显示并四舍五入,因此报告表中的十进制 GB 可能和终端显示的 G 不完全相同。
  • 未把不带日期、可能横跨多天的轮转文件直接算入某一天,例如 AI 的 robotMessageConsumer.log、.1–.10 和 Robot 的 gateway/swoole.log。否则会把历史内容重复归到当天。

统计命令形态如下,均为只读:

find /data/logs/dgj -type f \
  \( -name '*2026-08-26*' -o -name '*20260826*' \) -printf '%s\t%p\n'

find /data/logs/inner-robot -type f \
  \( -name '*2026-08-27*' -o -name '*20260827*' \) -printf '%s\t%p\n'

3. 26/27 号实际文件大小对比

3.1 AI 每台服务器合计

服务器26 号27 号变化
prod-dgj-php-ai-9219.021 GB23.081 GB+4.060 GB,+21.34%
prod-dgj-php-ai-9318.977 GB23.030 GB+4.052 GB,+21.35%
AI 合计37.999 GB46.111 GB+8.112 GB,+21.35%

3.2 AI 按日期日志文件对比

日志文件26 号合计27 号合计变化说明
robot-inquiry/kafka-YYYY-MM-DD.log37.960 GB37.457 GB-0.503 GB,-1.32%最大文件;入口完整 Kafka payload 仍保留
inner/robot_inquiry-YYYY-MM-DD.log未找到7.939 GB新增可见文件27 号日期文件;包含 RobotInquiry 链路节点
Services/info-YYYY-MM-DD.log未找到0.448 GB新增可见文件包含验证码处理、商品查询等 Services 日志
inner/simpleNameSer-YYYY-MM-DD.log未找到0.220 GB新增可见文件27 号新出现的日期文件
quote-manager/quote-manager-channel-YYYY-MM-DD.log0.037 GB0.038 GB+0.001 GB,+2.01%量小,属于流量波动
inner/smart_inquiry-YYYY-MM-DD.log未找到0.007 GB新增可见文件量小
robot_v2/im_inquiry-YYYY-MM-DD.log0.001 GB0.001 GB-43.14%绝对量很小
robot-inquiry/robot_inquiry_sort-YYYY-MM-DD.log0.001 GB0.001 GB-43.14%绝对量很小
其它日期文件约 0.0002 GB约 0.0002 GB基本不变包括 price、ImCenter、api 等

这里的“未找到”不是“确认当天没有产生日志”,而是服务器当前目录中没有找到对应日期命名文件。因此 AI 26→27 的目录总量不具备严格的同集合可比性。需要先确认 26 号相关日志是否被归档、清理、写入了轮转文件,或者 27 号发布后改变了日志文件命名/创建方式。

3.3 Robot 每台服务器合计

服务器26 号27 号变化
prod-dgj-robot-216.862 GB6.728 GB-0.134 GB,-1.96%
prod-dgj-robot-226.803 GB6.664 GB-0.139 GB,-2.05%
prod-dgj-robot-236.714 GB6.686 GB-0.028 GB,-0.42%
prod-dgj-robot-246.829 GB6.824 GB-0.005 GB,-0.07%
prod-dgj-robot-256.849 GB6.822 GB-0.027 GB,-0.40%
prod-dgj-robot-266.629 GB6.650 GB+0.021 GB,+0.32%
Robot 合计40.686 GB40.373 GB-0.313 GB,-0.77%

3.4 Robot 按日志节点对比

日志节点26 号合计27 号合计变化27 号占 Robot
gateway/info/20260827.INFO.log35.443 GB35.020 GB-0.423 GB,-1.19%86.74%
gateway/request/20260827.INFO.log4.104 GB4.215 GB+0.110 GB,+2.69%10.44%
gateway/webot/robot_20260827.log1.125 GB1.125 GB-0.0003 GB,-0.03%2.79%
gateway/trigger/*.WARNING.log0.011 GB0.012 GB+0.0004 GB,+3.14%0.03%
gateway/error/*.ERROR.log0.002 GB0.002 GB-0.00003 GB,-1.47%0.006%
gateway/trigger/*.NOTICE.log0.00001 GB0.000009 GB绝对量极小约 0%

Robot 的 27 号最大问题仍然是网关 info,其次是 request;本轮 dgj2.0 只修改 AI 应用侧代码,没有修改 Robot 网关项目,因此这里应作为后续独立治理项,而不是本次代码优化的效果证明。

4. 代码修改与日志内容对照

下面的示例均使用脱敏占位符,不包含真实客户、手机号、微信号或完整请求内容。

4.1 Kafka 消费入口:完整原始消息保留

代码位置:application/controllers/inner/moveMall/Robot.php:1880-1895。

当前代码仍然保留:

KzLogger::getLogger('robot-inquiry', 'kafka')->info('收到消息', [
    'topic' => $message->topic_name,
    'payload' => $message->payload,
]);

日志形态:

[INFO][kafka] RequestId#<入口请求ID># 收到消息
{"topic":"product.price...","payload":"{...完整原始消息...}"}

格式错误仍保留完整 payload:

KzLogger::getLogger('robot-inquiry', 'kafka')->error('消息格式错误', [
    'payload' => $message->payload,
]);

结论:这一份是整条链路的原始档案,本轮不删除。后续若要继续降低 AI 的 37 GB 大头,必须另行设计“原始消息低成本存储/压缩/按异常保留”方案,不能在下游重复日志上继续压缩来解决 Kafka 本身的占用。

4.2 parseNotify:去掉第二份完整 payload

代码位置:application/Providers/WechatRobot/Module/NotifyModule.php:15-30。

原来:

if ($this->isJson($notifyData)) {
    $logger && $logger->info($notifyData);
    $notifyData = json_decode($notifyData, true);
    // ...
}

原日志实质上是第二份完整微信消息:

[INFO][robot_inquiry] RequestId#<id>#
{"event":200,"out_app":"ZGJ","robot_wxid":"<robot>","...":"...大量字段..."}

现在:

$logger && $logger->info('parseNotify:解析微信消息', [
    'request_id' => $notifyData['request_id'] ?? '',
    'msg_id' => $notifyData['msg_id'] ?? '',
    'event' => $notifyData['event'] ?? '',
    'from_wxid' => $notifyData['from_wxid'] ?? '',
    'robot_wxid' => $notifyData['robot_wxid'] ?? '',
]);

现在的日志形态:

[INFO][robot_inquiry] RequestId#<id># parseNotify:解析微信消息
{"request_id":"<id>","msg_id":"<msg>","event":200,"from_wxid":"<from>","robot_wxid":"<robot>"}

保留能力:确认进入了解析节点,并可用 request_id/msg_id/event/robot_wxid 回到 Kafka 原始消息。

4.3 onMessage 开始:保留入口诊断信息,去掉重复 message

代码位置:application/Services/MoveMall/RobotInquirySer.php:104-115。

原来:

$this->logger->info('===== onMessage 开始 =====', [
    'message' => is_string($message) ? $message : json_encode($message, 256),
    'memory_limit' => ini_get('memory_limit'),
    'trace_id' => $this->getRequestId(),
]);

原日志会把 Kafka 已经记录过的完整 message 再写一次:

===== onMessage 开始 =====
{"message":"{...完整 payload...}","memory_limit":"2000M","trace_id":"<id>"}

现在:

$this->logger->info('===== onMessage 开始 =====', [
    'memory_limit' => ini_get('memory_limit'),
    'trace_id' => $this->getRequestId(),
]);

现在日志只表示“已经进入 onMessage”:

===== onMessage 开始 ===== {"memory_limit":"2000M","trace_id":"<id>"}

memory_limit 按原要求继续保留;trace_id 继续用于关联。入口节点没有被删除。

4.4 setContact 调用完成和初始化完成:保留节点,不重复对象

代码位置:application/Services/MoveMall/RobotInquirySer.php:255-277。

原来一条消息会重复打印:

onMessage:setContact done
{"contact":{...完整联系人...},"notify":{...完整消息...}}

onMessage:初始化环境完成
{"contact":{...完整联系人...},"conversation":{...会话...}}

现在:

onMessage:setContact done
onMessage:初始化环境完成

这两条日志的作用是判断“联系人初始化是否完成、环境初始化是否完成”,不需要再次携带对象。联系人查询和会话查询本身仍有独立节点。

4.5 loadConversation:只压缩 preConversation,保留当前 conversation

代码位置:application/Services/MoveMall/RobotInquiryBaseSer.php:236-256。

开始节点原来把 contact 再打印一遍:

loadConversation:开始加载会话
{"cvKey":"<key>","contact":{...完整联系人...}}

现在只保留会话键:

loadConversation:开始加载会话 {"cvKey":"<key>"}

完成节点原来同时打印两个完整对象:

loadConversation:会话加载完成
{"conversation":{...完整会话...},"preConversation":{...完整预会话...}}

现在的代码:

$this->logger->info('loadConversation:会话加载完成', [
    'conversation' => $this->conversation,
    'pre_conversation_id' => $this->preConversation['id'] ?? '',
    'pre_conversation_status' => $this->preConversation['status'] ?? '',
]);

现在的日志形态是:

loadConversation:会话加载完成
{"conversation":{...当前会话...},"pre_conversation_id":"<id>","pre_conversation_status":"<status>"}

这里没有删除当前 conversation,因此当前会话内容仍然可查;本轮只消除了 preConversation 完整对象的重复输出。由于 conversation 仍可能较大,它是下一批压缩候选,但不能在没有确认字段用途前直接删除。

4.6 verifyBindContactCode:完整 notify 改成链路摘要

代码位置:application/Services/MoveMall/WechatSer.php:946-966。

原来:

$this->logger->info('处理verifyBindContactCode', ['notify' => $notify]);

日志会在 Services/info 中写入完整 NotifyEntry,和入口 Kafka、解析节点、RobotInquiry 节点重复:

处理verifyBindContactCode
{"notify":{"event":200,"out_app":"ZGJ","robot_wxid":"<robot>","content":"...","...":"大量字段..."}}

现在:

$this->logger->info('处理verifyBindContactCode', [
    'request_id' => $notify->getRequestId(),
    'msg_id' => $notify->getMsgId(),
    'event' => $notify->getEvent(),
    'final_from_wxid' => $notify->getFinalFromWxId(),
    'robot_wxid' => $notify->getRobotWxId(),
]);

现在的日志形态:

处理verifyBindContactCode
{"request_id":"<id>","msg_id":"<msg>","event":200,"final_from_wxid":"<from>","robot_wxid":"<robot>"}

保留能力:能确认验证码处理函数被进入,并用 request_id/msg_id 回查原始输入。

当前限制:这条日志没有记录 has_code 或 code_in_range,因此单独看它不能判断正则是否提取到验证码、验证码是否命中范围。若以后需要定位“进入了验证码处理但没有绑定成功”,应优先查询后续绑定结果、Redis/绑定记录和错误日志;如果仍不足,再增加两个布尔字段,而不是恢复完整 notify。

4.7 未绑定客户:预期业务分支不打印无意义 trace

代码位置:application/Services/MoveMall/RobotInquirySer.php:318-325。

原来所有异常都打印堆栈:

消息处理失败
{"error":"未绑定客户","trace":"#0 ... RobotInquiryBaseSer.php(255) ..."}

现在:

$errorContext = ['error' => $error];
if ($error !== '未绑定客户') {
    $errorContext['trace'] = $exception->getTraceAsString();
}
$this->logger->error('消息处理失败', $errorContext);

预期业务分支变成:

[ERROR][robot_inquiry] RequestId#<id># 消息处理失败 {"error":"未绑定客户"}

未知 PHP 异常、外部接口异常、数据库异常仍保留 trace;本次不是“一律删除异常堆栈”。

4.8 searchWxList:统一公共方法,结果最多 500 字符

代码位置:

  • application/Services/BaseSer.php:108-138:新增 formatLogContext()。
  • application/Services/MoveMall/MoveMallGoodsSer.php:1184-1208:searchWxList-self 和 searchWxList 两处统一调用。

原来:

$this->logger->info('searchWxList:查询到商城商品数量', $res);

虽然日志文案写的是“商品数量”,实际写入的是完整 $res,可能包含数百 KB 的 rows/filter/category/car_list:

searchWxList:查询到商城商品数量
{"rows":[{...大量商品...}],"filter":{"category":[...],"car_list":[...]},"...":"..."}

现在:

$this->logger->info(
    'searchWxList:查询到商城商品数量',
    $this->formatLogContext($res)
);

统一方法的行为:

  1. JSON 序列化数据。
  2. 使用 mb_strlen/mb_substr 按 UTF-8 字符截断。
  3. 最多保留 500 个字符,超出时保留 497 个字符并追加 ...。
  4. 缺少 mbstring 时退化为 strlen/substr,仍然限制上限。
  5. JSON 序列化失败只记录短错误提示。
  6. 只改变日志上下文,不改变原始 $res,后续业务仍使用完整返回值。

优化后的形态:

searchWxList:查询到商城商品数量
{"result":"{\"rows\":[{...前497字符}..."}

这里“500 字符”指 result 字段中的序列化内容上限,日志前缀、时间、RequestId 和字段名会额外占少量字符。预发已验证超长 result 严格截断并以 ... 结尾,业务接口仍返回 success。

5. 已完成优化与未完成高量节点

5.1 已完成

日志节点改动排查能力
parseNotify:解析微信消息完整 notify 改为 5 个链路字段能确认解析节点、消息和机器人,完整内容回 Kafka 入口查
onMessage 开始删除重复完整 message,保留 memory_limit/trace_id能确认进入处理,并继续串联链路
onMessage:setContact done删除完整 contact/notify保留节点标志,联系人详情由独立节点查
onMessage:初始化环境完成删除完整 contact/conversation保留初始化完成标志,会话由会话节点查
loadConversation:开始加载会话删除重复 contact,保留 cvKey可核对会话键生成
loadConversation:会话加载完成保留 conversation,preConversation 改为 ID/状态仍可判断主会话和预会话状态
verifyBindContactCode完整 notify 改为 request/msg/event/微信 ID 摘要能回查入口原文,不再在 Services 重复存储
未绑定客户删除预期业务异常 trace错误原因保留,未知异常 trace 不丢
searchWxList 两处公共 500 字符截断能看结果结构开头,业务返回值不变

5.2 当前仍然较大、没有在本批删除的节点

节点/文件当前状态为什么不能直接删除下一步
robot-inquiry/kafka-YYYY-MM-DD.log27 号约 37.46 GB,AI 最大文件目前是唯一完整原始消息证据单独设计压缩/对象存储/异常保留策略;必须先定义“一条消息完整证据”的保存周期
inner/robot_inquiry-YYYY-MM-DD.log27 号约 7.94 GB多个业务节点仍在这里汇聚先按文案统计;优先处理完整 contact、conversation、商品数组
setContact:设置联系人当前仍打印完整 $this->contact需要保留联系人进入和服务站匹配证据,但不需要完整对象改为 contact_id/sid/chat_group_id/wxid/wxname 摘要,异常保留绑定站点差异
loadConversation:会话加载完成当前仍打印完整 $conversation用户要求当前 conversation 暂时保留统计内部字段后只保留 cv ID、状态、消息条数、最后更新时间等摘要
setConversationRecord:生成会话记录当前仍可能打印完整 $data需要证明记录是否生成及记录 ID保留 record/cv/contact/sid、内容长度、关键类型,删除完整 source/text/keyword
处理optionPrivateChat当前仍可能打印完整 notify需要确认是否进入验证码/私聊分支只保留 message/event/微信 ID/content_length
Robot gateway/info27 号约 35.02 GB,占 86.74%属于 Robot 网关项目,本轮未改单独建立 Robot 网关日志治理任务
Robot gateway/request27 号约 4.21 GB,占 10.44%请求审计需要保留,但不一定要完整 body保留 URL、状态、耗时、request_id;body 摘要/异常保留

5.3 VinAudit 请求/响应整包:当前量级与治理方案

当前量级

生产 Kibana 统计窗口为 2026-09-09 10:00~10:15,匹配 VinAudit 请求和响应整包日志:

指标结果
日志条数95,608 条
日志字符量1,858.9M
占窗口总日志量36.9%
平均单条约 19.4KB

该口径包含请求和响应,不等同于全天磁盘量。当前样例日志来源为 prod-dgj-vinaudit 的 providers/VinAudit 日志。

当前记录方式

DGJ2 每次同步调用分别记录:

请求:url + headers + data
响应:完整 response 原文

请求和响应通过同一个 requestId 关联。当前完整响应主要来自:

接口大字段
/product/search商品、车型、筛选项、属性
/product/getAttributes属性树、车型适配
/product/images图片 URL 数组
/product/get_attributes_by_sku_ids批量 SKU 属性

Sale 服务的 VinAudit Provider 也会把 config 和 responseBody 作为一条 http_client 事件整包记录,因此 DGJ2 和 Sale 两侧需要分别治理。

建议改法

场景保留内容处理方式
正常成功RequestId、接口、耗时、业务码、查询条件、返回数量、关键 ID不记录完整商品/车型/属性/图片数组,改为摘要
慢请求上述摘要 + 完整脱敏请求/响应按可配置耗时阈值保留
HTTP/业务异常请求条件、业务码、错误信息、异常堆栈、完整脱敏响应保留整包,便于定位失败原因
临时排查指定 RequestId 的完整脱敏请求/响应通过临时开关精准采集,不扩大正常日志量

成功日志只需保留 products_count、car_count、attribute_count、image_count 等数量字段,以及 VIN、SKU、分类等关键查询条件。sign、Authorization、完整 User-Agent 和重复 IP 不写入正常日志。

业务影响边界

日志摘要只能作用于日志变量,原始响应仍原样交给 Sale/DGJ 业务解析;不能用摘要内容替换业务 $response。这样不会改变商品、车型、属性和图片的实际返回,也不会改变超时、异常和重试逻辑。

落地顺序

  1. 先按接口拆分请求量、响应量、字符量和最大单条,确认第一优先级接口。
  2. 优先改 /product/search、/product/getAttributes、/product/images 的成功日志摘要。
  3. 保留超时、非 2xx、业务码异常、解析失败和慢请求的完整脱敏日志。
  4. 预发验证正常、空结果、超时、业务异常和 JSON 异常,再用相同 15 分钟窗口复测字符量、平均单条和最大单条。

6. 已有同窗口验证证据

下面是上线后已经记录的 15 分钟/短窗口证据,不能和 26/27 日文件总量混为同一个指标,但可以证明“单条日志是否变小”。

日志点优化前样本优化后样本结果
robot_inquiry 合计88.59M 字符1.81M 字符约下降 97.96%
onMessage 开始 平均单条52,893 字符156 字符完整 message 已去掉
loadConversation:会话加载完成 平均单条2,411 字符约 755 字符preConversation 已摘要,conversation 仍保留
消息处理失败 平均单条929 字符106 字符未绑定客户不再打印 trace
searchWxList 预发单条最大历史约 220KBresult 最多 500 字符已验证 ... 截断

这些数据说明本批修改确实减少了重复大对象,但 AI 日文件总量仍被 Kafka 完整 payload 主导;如果要让 AI 从几十 GB 继续显著下降,必须处理原始入口证据的存储策略,单纯继续删除下游节点会逐渐损失排查能力。

7. 一条消息如何排查

Kafka 收到消息(唯一完整 payload,入口证据)
        |
        +--> onMessage 开始(trace_id、memory_limit)
        |
        +--> parseNotify(request_id、msg_id、event、微信 ID)
        |
        +--> setContact(bindWxId、联系人摘要、服务站匹配)
        |
        +--> loadConversation(cvKey、conversation、pre 会话 ID/状态)
        |
        +--> 商品/库存/排序(数量、ID、耗时;当前仍有部分完整对象)
        |
        +--> 会话记录(record/cv/contact ID;当前仍需继续压缩)
        |
        +--> onMessage 结束 或 消息处理失败

推荐查询顺序:

  1. 先按 Kafka 入口的 request_id 或内部 RequestId 找到完整原始消息。
  2. 用 msg_id 确认确实是同一条微信消息,避免只依赖可能在不同系统重新生成的 request ID。
  3. 查 parseNotify、setContact、loadConversation,判断消息解析、联系人、会话分别停在哪一步。
  4. 查 sid/contact_id/cv_id/record_id,定位业务数据。
  5. 遇到验证码绑定问题,查 verifyBindContactCode 后续绑定结果;当前摘要日志本身不记录验证码命中情况。
  6. 遇到未知异常,查 消息处理失败 的 error + trace;遇到“未绑定客户”,只看业务原因和绑定微信 ID,不需要堆栈。

8. 风险判断

8.1 已验证为低风险

  • 删除的都是日志上下文字段,不改变 $message/$notify/$contact/$conversation/$res 的业务变量。
  • Kafka 完整入口消息没有删除;格式错误仍保留完整 payload。
  • memory_limit 按要求保留。
  • 未知异常仍保留 trace;只对明确的“未绑定客户”去掉堆栈。
  • formatLogContext() 只在日志参数中序列化和截断,searchWxList 后续仍使用原始返回值。
  • searchWxList 与 searchWxList-self 两条路径都使用公共方法,避免只修改一条路径。

8.2 需要继续关注

  • AI 26/27 日期文件集合不一致,不能仅用目录总量判断收益;需要先确认旧文件归档和日志配置。
  • 当前 setContact:设置联系人 仍输出完整 contact,说明下游重复大对象尚未全部清除。
  • 当前 loadConversation:会话加载完成 保留完整 conversation,符合当前保守策略,但仍是后续大日志候选。
  • verifyBindContactCode 当前没有验证码匹配结果字段;排查绑定失败时必须依赖后续日志或数据,不能只看这一条。
  • Kafka 完整 payload 是 AI 的不可忽略存储底座;如果改变保存方式,必须验证 RequestId、msg_id、原始 payload 可回查和保留周期。
  • Robot 网关本轮未修改,不能把 Robot 27 号的轻微下降写成 dgj2.0 代码收益。

8.3 AI 26号日志完整性专项核查

核查范围

本次直接只读检查 prod-dgj-php-ai-92(10.80.21.92) 和 prod-dgj-php-ai-93(10.80.21.93) 的 /data/logs/dgj,核对 2026-08-26 日期文件、2026-08-27 对照文件、压缩归档和进程仍持有的 deleted-open 文件;没有执行删除、重启或其他线上写操作。

日期文件结果

主机26号可见日期文件合计其中 Kafka 主日志26号缺失的关键日期文件
AI-9219,021,473,480 bytes(约 19.02GB)19,001,506,225 bytes(约 19.00GB)inner/robot_inquiry、Services/info、inner/simpleNameSer、inner/smart_inquiry
AI-9318,977,440,677 bytes(约 18.98GB)18,958,491,173 bytes(约 18.96GB)inner/robot_inquiry、Services/info、inner/simpleNameSer、inner/smart_inquiry

两台机器的 26 号 Kafka 文件都存在,并且都在 26 号 23:59 左右完成写入;因此不能判断为“26 号 AI 日志全部被删除”。但是,26 号四类关键业务日期文件在两台机器上同时缺失,说明按 /data/logs/dgj 日期文件统计出来的 26 号总量不是完整的 AI 应用日志基线。

作为对照,27 号两台机器均出现了这些文件:inner/robot_inquiry 各约 3.95–3.99GB、Services/info 各约 223–224MB、inner/simpleNameSer 各约 109–111MB,说明 26/27 的日志文件集合发生过变化,不能直接用两天目录总量下结论。

是否发现删除痕迹

检查项AI-92AI-93判断
/data/logs 下常见压缩归档未发现未发现没有在本机找到 26 号压缩备份
deleted-open 唯一 inode26 个26 个两台机器都有被 unlink 的滚动日志
deleted-open 文件大小合计134,908,087 bytes(约 128.7MiB)135,912,289 bytes(约 129.6MiB)量级约 260MiB,无法解释约 38GB 的 Kafka 主体
deleted-open 路径robotMessageConsumer.log.10robotMessageConsumer.log.10属于 Supervisor 滚动 stdout/stderr,不是带 26 日期的业务文件

根因倾向

两台 AI 的 Supervisor 配置都为 robotMessageConsumer 启动 36 个进程,并让所有进程的 stdout 和 stderr 共享同一个 /data/logs/dgj/robotMessageConsumer.log,且没有显式配置独立的轮转参数。Supervisor 默认注释配置为单文件约 50MB、保留 10 个备份;在多进程共享同一轮转文件时,容易出现多个进程各自持有同名 .10、旧 inode 已从目录 unlink 但仍被进程占用的情况。

这可以确认“部分滚动 stdout/stderr 历史内容存在被清理/轮转的风险”,但当前证据不能证明这些 deleted-open 内容就是 26 号四类业务日期文件,也不能证明 26 号 19GB Kafka 文件被删除。

结论和后续动作

  1. 26 号 AI 日志统计应标记为“日期文件集合不完整”,不能把约 37.99GB 当成完整日总量。
  2. 26 号 Kafka 主日志仍在,是目前最主要的完整原始消息证据;两台机器合计约 37.96GB。
  3. 需要优先核对 Monolog channel 的文件创建规则、26 号发布/重启时间和采集端索引,确认四类日期文件是“当日未生成”还是“后续被清理”。
  4. Supervisor 配置需要单独整改:为 36 个消费者设置按进程区分的 stdout/stderr 文件,或将正常 stdout 关闭、把格式错误/异常改为结构化应用日志;在整改前不能把当前滚动文件当作可完整回溯的审计证据。
  5. 本次核查没有执行线上写操作;若要恢复已 unlink 文件,只能在明确批准后制定取证方案,避免直接重启或关闭进程导致仍占用 inode 的内容彻底释放。

9. 下一阶段落地顺序

P0:先处理 AI 应用侧仍然重复打印完整对象

  1. setContact:设置联系人:保留 contact_id/sid/chat_group_id/wxid/wxname 和匹配结果,删除完整 contact。
  2. setConversationRecord:生成会话记录:保留 record/cv/contact/sid、内容长度、关键词类型,删除完整 source/text/keyword。
  3. 处理optionPrivateChat:保留事件、微信 ID、内容长度和分支结果,删除完整 notify。
  4. 商品查询/库存/排序:保留数量、ID、原因、耗时;删除循环内完整商品数组。

P1:明确原始消息证据的成本边界

  1. 入口仍保留完整原始消息,但评估压缩、独立索引、对象存储或按异常保留。
  2. 统一原始消息和下游日志的关联键:request_id + msg_id + sid,必要时加 record_id/cv_id。
  3. 设定保留策略:正常消息和异常消息的保留时长、查询入口、恢复流程必须明确。

P2:单独治理 Robot 网关项目

  1. gateway/info 先按 35.02 GB 文件拆出“完整 Kafka 回调业务体”“私聊消息过滤”“发送/回调结果”等文案。
  2. gateway/request 保留 URL、状态、耗时、request_id,正常请求 body 截断,异常请求保留必要上下文。
  3. gateway/webot 的 HTTP debug 报文单条较大,应改为开关或仅异常采集;这项不能通过修改 dgj2.0 代码完成。

10. 汇报时可以直接使用的表述

8 月 27 日完成 DGJ2 AI 报价日志的第一阶段治理:保留 Kafka 消费入口唯一完整原始消息,删除下游部分节点重复的完整 message、notify、contact 和 preConversation;未知异常仍保留堆栈,预期业务异常只保留错误原因;商品查询返回统一限制为 500 字符。服务器实际文件统计显示,AI 27 号可明确归属日期的日志约 46.11 GB,Robot 网关约 40.37 GB。AI 总量与 26 号相比增加,主要是 27 号新增了独立日期日志文件,不能直接判定优化失效;同名 Kafka 大文件下降约 1.32%。当前最大剩余来源是 Kafka 入口完整 payload 和 AI 内部仍保留的完整 contact/conversation/商品对象,下一阶段将优先在不丢失 RequestId、msg_id、业务 ID 和异常证据的前提下继续摘要化。