Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[iceworks] process log optimization #2452

Merged

Conversation

chenbin92
Copy link
Collaborator

@chenbin92 chenbin92 commented Jul 15, 2019

问题

目前在 iceworks 启动调试服务等子进程时会有 「日志丢失」问题,导致数据流输出不全,造成用户以为启动失败的困惑,一直没有响应

image

定位

经排查定位发现是对进程的输出流监听缺失导致,之前只监听了 stdout 流而没有监听 stderr 流:

image

分析

子进程的数据流分为:stdoutstderrstdiostdin等情况,这里只考虑stdoutstderr 两种, 那么对于stdoutstderr输出时,具体什么样的数据会进入到对应的类型,做一个简单的测试:

测试代码

// test.js
console.log('log');
console.warn('warn');
console.debug('debug');
console.error('error');
console.info('info');

执行文件

// index.js

const child = await execa('node', ['./test.js']);
console.log('result:\n', child);

输出结果

  • stdout:非错误信息输出到 stdout,包含 log 和 info
  • stderr: 错误信息到stderr,包含 warn 和 error
    image

TODO

  • webpack 执行中数据流进度持续输出
  • npm install 执行中数据流持续输出
  • 进度条数据控制在一行输出在另外一个 MR 实现

image

最终效果

  • 启动调试服务可以看到实时进度条,在另外一个 MR 已经将持续的进度流数据优化成一行输出
    image

  • npm install 持续输出对应的流数据

image

@chenbin92 chenbin92 changed the title [iceworks] process log optimization [WIP][iceworks] process log optimization Jul 15, 2019
@chenbin92 chenbin92 self-assigned this Jul 15, 2019
@luhc228
Copy link
Collaborator

luhc228 commented Jul 15, 2019

那构建进度的信息 如下图 解释成warn 和 error,是这样理解?感觉说不通吧
image

@chenbin92
Copy link
Collaborator Author

那构建进度的信息 如下图 解释成warn 和 error,应怎样理解?
image

弄清楚这个进度的信息具体是从哪里打印出来的

@luhc228
Copy link
Collaborator

luhc228 commented Jul 15, 2019

那构建进度的信息 如下图 解释成warn 和 error,应怎样理解?
image

弄清楚这个进度的信息具体是从哪里打印出来的

这个信息是从stderr中输出的,这个我测试过了。

@chenbin92 chenbin92 changed the base branch from iceworks/release-3.0.0-beta.4 to iceworks/release-3.0.0-beta.5 July 15, 2019 13:42
@chenbin92
Copy link
Collaborator Author

chenbin92 commented Jul 16, 2019

问题描述

  • 启动调试服务进度流数据丢失
  • 执行 npm install 进度流数据丢失

上述两个问题本质上是同一类问题,问题原因:

在执行对应的子进程时, stdout 和 stderr 输出的只包含 loginfowarnerror 四种类型的数据,而类似 webpack 实时编译的流数据,npm install 的流数据不在 stdout 和 stderr 中输出,需要自行处理。

实时编译效果

image

核心实现代码

通过 webpack ProgressPlugin new webpack.ProgressPlugin 拿到编译的实时数据, 使用 node-progress 将数据处理成进度条,如果是 TTY 环境则输出,很显然,在 iceworks 的场景下不符合 tty 环境的要求,故而在 iceworks 界面上进度条数据丢失:

function SimpleProgressPlugin(options) {
  if (!process.stderr.isTTY) {
    return function () {};
  }

  if (options) {
    messageTemplate = options.messageTemplate || messageTemplate;
    progressOptions = objectAssign(progressOptions, options.progressOptions);
  }

  var progressBar = new progress(messageTemplate, progressOptions);

  return new webpack.ProgressPlugin(function(percentage, msg) {

    // node-progress: https://github.com/visionmedia/node-progress/blob/master/lib/node-progress.js#L121
    progressBar.update(percentage, { msg: msg });
  });
}

注: npm install 问题与上述一样

解决方案

上述问题本质上是如何使用 Node 的 tty 模块实现一个终端读写流的效果,将流数据实时传输到终端上。

方案一

描述

使用 node-ptyxterm.js 可以很好的结合,如同它的介绍一样:

forkpty(3) bindings for node.js. This allows you to fork processes with pseudoterminal file descriptors. It returns a terminal object which allows reads and writes.

node-pty 实现了终端流数据的读写,提供 pty.spawn 命令执行子进程,通过子进程的 write 方法可以将数据实时写在终端上,进而实现了终端的效果。

var pty = require('node-pty');

var ptyProcess = pty.spawn(shell, [], {
  name: 'xterm-color',
  cols: 80,
  rows: 30,
  cwd: process.env.HOME,
  env: process.env
});

ptyProcess.on('data', function(data) {
  process.stdout.write(data);
});

ptyProcess.write('ls\r');
ptyProcess.resize(100, 40);
ptyProcess.write('ls\r');

优点:

  • 能提供和终端一样媲美的效果

缺点:

  • node-pty 使用 C 语言编写,依赖 Python 和 C ++编译器,比较致命的环境 building

方案二(已实现)

效果图

在 ice-scripts 中通过 node-ipc 和 iceworks 进行通信,将 获取到的 webpack 编译的实时数据传输到 iceworks ,在 iceworks 中进行格式化处理并自定义输出,相当于自定义一个进度条效果。

流数据如下,只需要进一步格式化数据即可:

image

优点

  • 相比 node-pty 无依赖环境和编译的问题

缺点

  • 自定义输出,效果不如终端输出的效果

方案三

在 ice-scripts 工程中劫持 webpack ProgressPlugin 编译的数据,通过 log 的形式输出即可挂载到 stdout 上,相比方案二无需通过 node-ipc 进程传输,实现上更轻量和解耦

image

综上

方案一:node-pty 太依赖环境 python 和 c++,问题会更多,可能80%的用户都解决不了环境问题,这个代价太大

方案二,三:方案相对较轻,通过对数据进行处理自定义输出,透出基本的信息让用户有所感知。

追溯上述问题的本质还是 网络问题,因为网络问题故而需要进度条提示,然后即使有进度条并没有解决实际的问题,不然也不会有 cnpm 的市场。如果需要彻底解决这个问题,既不强依赖环境,又完美适配终端的体验,可能需要自己基于 TTY 模块实现一个终端,目前来看,这个投入产出比太低。

@chenbin92 chenbin92 changed the base branch from iceworks/release-3.0.0-beta.5 to iceworks/release-3.0.0-beta.6 July 17, 2019 04:09
@chenbin92 chenbin92 removed the request for review from imsobear July 17, 2019 04:14
@chenbin92 chenbin92 changed the title [WIP][iceworks] process log optimization [iceworks] process log optimization Jul 17, 2019
@imsobear
Copy link
Collaborator

imsobear commented Jul 17, 2019

再更新下一些结论:

  • TTY 即终端环境,通过 spawn/exec 等 API 调用命令执行不是 TTY 环境
  • webpack 的进度日志输出:
    • webpack 的进度日志可以通过两种方式输出:
      1. 内置的 ProgressPlugin 代码 直接输出到 stderr
      2. webpack-simple-progress-plugin,非 TTY 环境日志不会输出,TTY 的环境会依赖 npm 包 progress 格式化成进度条形态
    • 方案:ice-scripts 里非 TTY 的环境使用 ProgressPlugin,TTY 环境使用 SimpleProgressPlugin,应该跟 vue-cli 是一致的,代码,这样在非 TTY 的环境里也会输出详细进度日志,但看起来会有点乱,未来可以将这部分日志在前端可视化成进度条
  • npm 的进度日志输出:
    • 基于 npmlog,通过 --loglevel 参数指定输出等级,默认是 notice(npm config get loglevel 可以看到),改成 silly 即可输出详细日志
    • 在 TTY 的环境里无论 loglevel 是什么都会把日志输出给 gauge,gauge 的职责跟 SimpleProgressPlugin 有点类似,根据特征匹配格式化成进度条
    • 方案:通过 --loglevel 参数输出详细日志

@chenbin92
Copy link
Collaborator Author

再更新下一些结论:

  • npm 的进度日志输出:

    • 基于 npmlog,通过 --loglevel 参数指定输出等级,默认是 silent(npm config get loglevel 可以看到),改成 silly 即可输出详细日志

@imsobear 默认是 notice

image

@chenbin92 chenbin92 requested a review from imsobear July 17, 2019 05:07
@ClarkXia ClarkXia merged commit a63ac68 into iceworks/release-3.0.0-beta.6 Jul 17, 2019
@delete-merged-branch delete-merged-branch bot deleted the iceworks/process-log-optimization branch July 17, 2019 07:19
@chenbin92 chenbin92 mentioned this pull request Jul 17, 2019
6 tasks
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants