You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jenkins Pipeline并行解析日志文件及trim()报错解决

问题描述

在Jenkins Pipeline中尝试并行执行耗时约1小时的script.sh并实时解析其日志,已编写对应Bash脚本和Pipeline代码,但运行时触发trim()方法报错,具体错误信息如下:

Also:   org.jenkinsci.plugins.workflow.actions.ErrorAction$ErrorId: bd5e3fed-a88b-4ea2-ac3e-7a8e799a30f1
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.lang.Integer.trim() is applicable for argument types: () values: []
Possible solutions: wait(), grep(), wait(long), grep(java.lang.Object), times(groovy.lang.Closure), is(java.lang.Object)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:159)

相关代码

script.sh

#!/bin/bash

# 定义ANSI颜色码
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
BLUE="\033[0;34m"
RESET="\033[0m"

# 打印带颜色文本的函数
print_colored_text() {
    local color="$1"
    local text="$2"
    echo -e "${color}${text}${RESET}"
}

# 打印不同颜色的文本
print_colored_text "$RED" "This is red text."
print_colored_text "$GREEN" "This is green text."
print_colored_text "$YELLOW" "This is yellow text."
print_colored_text "$BLUE" "This is blue text."

# 打印带颜色的提示信息
echo -e "${RED}Error:${RESET} Something went wrong."
echo -e "${GREEN}Success:${RESET} Operation completed successfully."
echo -e "${YELLOW}Warning:${RESET} This action is irreversible."
echo -e "${BLUE}Info:${RESET} Please read the documentation."

# 重置颜色设置
echo -e "${RESET}"

Jenkins Pipeline 原代码

pipeline {
    agent any

    stages {
        stage('Execute Bash Script') {
            steps {
                script {
                    // 启动长耗时脚本并将输出重定向到文件
                    sh(script: 'chmod +x script.sh && ./script.sh > script_output.log &', returnStatus: true)

                 
                    def process = sh(script: 'tail -f script_output.log & echo $!', returnStatus: true, returnStdout: true).trim()
                    echo "ON Next One"
                    def pid = process.stdout.trim()

                    echo "Next one again"
                    while (true) {
                        def status = sh(script: "ps -p $process -o etime=", returnStatus: true, returnStdout: true).stdout.trim()

                        if (status.empty() || status.startsWith('+')) {
                            // 脚本已完成或日志文件停止更新
                            break
                        }

                        sleep 30 // 根据需要调整休眠时长
                    }

                    // 终止tail进程
                    sh(script: "kill $pid", returnStatus: true)

                    // 检查脚本输出
                    def scriptOutput = readFile('script_output.log')
                    if (scriptOutput.contains("This is red text.")) {
                        echo "Parsing completed successfully."
                    } else {
                        echo "Parsing failed."
                    }
                }
            }
        }
    }
}
解决方案

报错原因分析

报错核心是**trim()方法被错误调用在了Integer类型变量上**:

  • 当sh命令同时设置returnStatus: true和returnStdout: true时,返回的是一个包含status(整数)和stdout(字符串)的复合对象,而非直接返回标准输出字符串。
  • 原代码中def process = sh(...).trim()错误地对这个复合对象调用trim(),后续又错误地用process作为PID执行ps命令,导致类型混乱触发报错。

修复后的Pipeline代码

pipeline {
    agent any

    stages {
        stage('Execute Bash Script') {
            steps {
                script {
                    // 启动后台脚本并将输出写入日志文件
                    sh(script: 'chmod +x script.sh && ./script.sh > script_output.log &', returnStatus: true)

                    // 获取tail进程的PID:直接取标准输出并去除首尾空白
                    def tailOutput = sh(script: 'tail -f script_output.log & echo $!', returnStdout: true).trim()
                    def tailPid = tailOutput

                    echo "Tail进程PID: ${tailPid}"

                    // 轮询检查目标脚本是否仍在运行
                    while (true) {
                        // 查找script.sh的进程状态,避免误查tail进程
                        def scriptStatus = sh(script: "pgrep -f script.sh || echo ''", returnStdout: true).trim()
                        
                        if (scriptStatus.isEmpty()) {
                            // 目标脚本已结束,退出循环
                            break
                        }

                        // 实时解析日志内容(可根据需求添加自定义解析逻辑)
                        def currentLog = readFile('script_output.log')
                        if (currentLog.contains("Error:")) {
                            echo "检测到错误日志"
                            // 可根据需求添加告警或终止流程逻辑
                        }

                        sleep 30 // 调整轮询间隔
                    }

                    // 终止tail进程
                    sh(script: "kill ${tailPid}", returnStatus: true)

                    // 最终检查日志结果
                    def finalOutput = readFile('script_output.log')
                    if (finalOutput.contains("This is red text.")) {
                        echo "日志解析完成,结果正常。"
                    } else {
                        echo "日志解析失败。"
                    }
                }
            }
        }
    }
}

关键修复点

  1. 修正sh命令返回值处理:去掉returnStatus: true,直接获取标准输出字符串并调用trim(),避免对复合对象操作。
  2. 正确监控目标脚本状态:用pgrep -f script.sh替代检查tail进程,确保监控的是实际运行的目标脚本而非日志监听进程。
  3. 优化实时解析逻辑:在轮询过程中直接读取日志文件并执行解析,实现真正的实时监控。

替代方案:使用Parallel步骤实现并行执行

如果需要更简洁可靠的并行任务和日志处理,可使用Jenkins的Parallel步骤同时运行脚本和日志解析:

pipeline {
    agent any

    stages {
        stage('Parallel Execution & Log Parsing') {
            steps {
                script {
                    // 运行目标脚本的闭包
                    def scriptRun = {
                        sh './script.sh'
                    }

                    // 实时解析日志的闭包
                    def logParse = {
                        sleep 10 // 等待脚本启动生成日志
                        while (true) {
                            if (fileExists('script_output.log')) {
                                def logContent = readFile('script_output.log')
                                // 自定义实时解析逻辑
                                if (logContent.contains("Success:")) {
                                    echo "实时检测到成功日志"
                                }
                            }
                            // 检查目标脚本是否仍在运行
                            def isRunning = sh(script: "pgrep -f script.sh || echo 0", returnStdout: true).trim()
                            if (isRunning == '0') break
                            sleep 30
                        }
                    }

                    // 并行执行脚本运行和日志解析任务
                    parallel(
                        "Run Script": scriptRun,
                        "Parse Log": logParse
                    )
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Neetesshhr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 04:00:49