jenkins简介

Jenkins 是一款非常流行的 CI/CD 工具,它提供了实时日志显示功能,使得用户可以在构建和部署过程中实时查看日志输出。

在 Jenkins 中,实时日志显示是通过控制台输出实现的。当用户启动构建任务时,Jenkins 会在后台执行构建过程,并将输出的日志信息实时显示在 Jenkins 的 Web 页面上。这样用户就可以在不离开 Jenkins 页面的情况下,实时查看构建任务的执行过程和输出信息。

Jenkins 的实时日志显示功能基于 HTTP 和 Ajax 技术实现。Jenkins 在后台使用一个持续的 HTTP 连接来不断传输控制台输出信息,而 Web 页面则使用 Ajax 技术来接收和显示这些信息。通过这种方式,Jenkins 可以实现高效的、实时的日志输出。

总的来说,Jenkins 的实时日志显示功能是通过持续的 HTTP 连接和 Ajax 技术来实现的,它可以帮助用户实时查看构建和部署过程中的日志输出,从而更好地了解任务的执行情况。

源码分析

Jenkins的实时日志显示是通过WebSocket实现的。Jenkins基于Java实现,使用了Jetty作为内嵌Web容器,因此使用Jetty提供的WebSocket API来实现实时日志显示功能。

具体来说,Jenkins在Web页面中使用了一个JavaScript库Stapler来处理Web请求。当用户请求查看某个Job的构建日志时,Jenkins会向后端发送一个异步请求,请求某个Controller来处理该请求。Controller会调用Build.getLogText()方法获取构建日志的文本内容,并通过Jetty提供的WebSocket API将文本内容以小块的形式发送给前端。前端通过WebSocket接收到文本块后,即可在Web页面中动态地显示出构建日志。

以下是大致的代码流程:

  1. 后端Controller处理Web请求:
public void doLog(StaplerRequest req, StaplerResponse rsp) throws IOException {
    // 获取构建对象
    Run<?, ?> build = getBuild();
    if (build == null) {
        rsp.sendError(HttpServletResponse.SC_BAD_REQUEST);
        return;
    }

    // 获取请求参数
    String start = req.getParameter("start");
    String end = req.getParameter("end");

    // 获取构建日志
    BuildLogStreamer streamer = new BuildLogStreamer(build.getLogText(), start, end);
    // 设置WebSocket响应头
    rsp.addHeader("X-Text-Size", String.valueOf(streamer.length()));
    rsp.addHeader("X-More-Data", "true");
    // 开始发送构建日志文本
    streamer.stream(req, rsp);
}
  1. BuildLogStreamer类实现构建日志的流式发送:
public class BuildLogStreamer extends AbstractStream {

    private final String logText;
    private final long offset;
    private final int maxLength;

    public BuildLogStreamer(String logText, String start, String end) {
        this.logText = logText;
        // 解析请求参数,计算文本起始偏移量和文本最大长度
        this.offset = StringUtils.isBlank(start) ? 0 : Long.parseLong(start);
        int endOffset = StringUtils.isBlank(end) ? logText.length() : Integer.parseInt(end);
        this.maxLength = endOffset > logText.length() ? logText.length() : endOffset;
    }

    @Override
    protected void write(OutputStream os) throws IOException {
        // 发送文本块
        try (Writer writer = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
            writer.write(logText.substring((int) offset, maxLength));
        }
    }

    @Override
    public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException {
        rsp.setStatus(HttpServletResponse.SC_OK);
    }

    @Override
    public long length() throws IOException, InterruptedException {
        return maxLength - offset;
    }

}
  1. 前端JavaScript代码实现WebSocket接收文本块并更新Web页面:
// 初始化WebSocket连接
var socket = new WebSocket(url);
socket.onopen = function(event) {
    // 连接成功,发送初始请求参数
    socket.send("start=" + startOffset + "&end=" + endOffset);
}
socket.onmessage = function(event) {
    // 接收到文本块,更新Web页面
    var data = event.data;
    outputBuffer.push(data);
   
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐