Skip to content

fix: optimize stdout#2562

Open
StartE wants to merge 8 commits into
alibaba:mainfrom
StartE:yili/fix_stdout
Open

fix: optimize stdout#2562
StartE wants to merge 8 commits into
alibaba:mainfrom
StartE:yili/fix_stdout

Conversation

@StartE
Copy link
Copy Markdown
Collaborator

@StartE StartE commented May 20, 2026

问题背景

  • C++ InputContainerStdio 处理 Docker JSON 格式容器日志时,Docker 运行时将超 16KB 的行拆成多条 partial log:

  • JSON 多行模式创建 JsonLogFileReader,会对日志进行错误\0分割,导致后续完全错乱


修复的缺陷

缺陷 1: Partial Log 不标记

根因ParseDockerJsonLogLine 只去掉末尾 \n,没有利用"有无 \n"这一信息设置 PartLogFlag。

修复

// content: log 字段末尾有 \n 为 Full,无 \n 为 Partial
bool isPartialLog = !content.empty() && content.back() != '\n';
if (!content.empty() && content.back() == '\n') {
    content = StringView(content.data(), content.size() - 1);
}
sourceEvent.SetContentNoCopy(containerLogKey, content);
if (isPartialLog) {
    sourceEvent.SetContentNoCopy(PartLogFlag, StringView());
    logGroup.SetMetadata(EventGroupMetaKey::HAS_PART_LOG, PartLogFlag);
}

缺陷 2: JSON 多行模式创建 JsonLogFileReader

根因CreateInnerProcessorsSetRequiringJsonReaderFlag(true) 导致使用 JsonLogFileReader,其 RemoveLastIncompleteLog 在容器格式剥离前做 {} 配对,破坏 CRI/Docker 头部。

修复:移除 SetRequiringJsonReaderFlag(true),改为 Processor 层 MergeByJson 处理。

缺陷 3: DockerJsonFileParser 无条件 fullLine=true

根因parseLine 不检测 log 字段有无 \ncheckContainerType 给 DockerJsonFileParser 分配 buffer=0。

修复

  • parseLine: fullLine = hasNewline(有 \n 为 Full,无为 Partial)
  • checkContainerType: buffer 分配 LogFileReader::BUFFER_SIZE
  • GetLastLine: 添加 Phase 2 P 行合并逻辑 + mergeLines 方法

新功能: MergeByJson(Phase 4)

在容器格式剥离 + P/F 合并之后,通过 {} 大括号配对将多行 JSON 日志合并为一条事件。

Pipeline 变化

Split(\n) → ParseContainerLog → MergeByFlag → [旧: SplitChar='\0' 死代码]
Split(\n) → ParseContainerLog → MergeByFlag → [新: MergeByJson 块合并]

核心实现 — 大括号状态机:

bool inQuote = false;
for (size_t i = 0; i < content.size(); ++i) {
    char c = content[i];
    switch (c) {
        case '\\': if (inQuote) ++i; break;        // 转义跳过
        case '"':  inQuote = !inQuote; break;       // 引号状态切换
        case '{':  if (!inQuote) braceDepth++; break;
        case '}':  if (!inQuote) braceDepth--; break;
    }
}
// braceDepth <= 0 → JSON 块完成,MergeEvents 输出
// accumulatedSize > maxSize → 强制输出 + SPLIT_LOG_FAIL_ALARM
// 批次末尾未闭合 → 不丢弃,合并输出

测试覆盖(14 个新增测试方法)

Phase 1: Docker JSON Partial Log 标记与合并【processor层】

测试方法 验证点
TestDockerJsonPartialLogBasic ParseContainerLog 对 partial 设 PartLogFlag + HAS_PART_LOG
TestDockerJsonPartialLogWithSplit 3 步管线 P+P+F → 合并为 1 条
TestDockerJsonPartialLogWithSplitAndRegex 4 步管线 P/F 合并 → 正则合并堆栈

Phase 3: DockerJsonFileParser P/F 行支持【fileReade层】

测试方法 验证点
TestLastDockerJsonFileSingleLine needSingleLine=true: 8 种 P/F 组合(跳过 P 找 F)
TestLastDockerJsonFileMerge needSingleLine=false: 6 种 P/F 组合(P 行合并)

Phase 2: JSON 多行模式修复【reader + processor】

测试方法 验证点
TestCreateInnerProcessorsJsonMultilineNoJsonReader 不创建 JsonLogFileReader + step4 为 MergeByJson

Phase 4: MergeByJson 大括号状态机

测试方法 验证点
TestMergeJsonInit MergeType=json 初始化
TestMergeJsonSingleLineBlock 单行完整 JSON 不合并
TestMergeJsonMultiLineBlock 多行 JSON 块合并(6 行 → 1 条)
TestMergeJsonMultipleBlocks 连续多块各自独立合并
TestMergeJsonBraceInString 引号内 {} 不影响计数
TestMergeJsonEscapedQuote 转义 \" 不影响引号状态
TestMergeJsonOversized 超 maxSize 强制输出 + 告警
TestMergeJsonIncompleteAtEnd 批次末尾未闭合不丢弃

@StartE StartE changed the title optimize stdout fix: optimize stdout May 20, 2026
@StartE StartE requested a review from Takuka0311 May 20, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant