当前位置: 首页 > 科技观察

我有几个人知道持续集成系统的日志密码

时间:2023-03-17 09:59:19 科技观察

前言前段时间在使用TravisCI的时候,发现它的部署日志里面有很多彩色的日志。而且我们知道,这些可爱的颜色也会在使用命令行终端时出现。当然,我不是为了炸毁它而炸毁它。有实际作用,可以帮助我们快速定位问题!我对此很好奇,TravisCI是如何将这些彩色日志移动到浏览器中的呢?我猜想一定是不是通过识别关键词特征来完成的,因为那太low了。经过一番查询,我找到了一个好不容易找到的关键词,就是ANSIescapesequences。ANSI转义序列是带内信号的标准,用于控制光标位置、颜色和终端和终端仿真器上的一些其他选项。--Wikipedia通俗地说,就是那些终端输出的彩色文本,包含一些转义序列字符,但是我们看不到,被终端解析出来了。终端再将这些字符解析成我们现在看到的五颜六色的日志(包括一些颜色、下划线、粗体等)。比如我们在终端安装npm,切换git分支,运行时报错就可以看到。正是有了这些颜色,我们的调试效率大大提高了,哪些命令出错了,如何解决,一目了然。现在我们要做的就是如何将这些颜色日志输出到浏览器。在做这一步之前,我们首先要知道这些ANSI转义序列长什么样子?根据wiki可以知道,ANSI转义序列可以操作很多功能,比如光标位置、颜色、下划线等选项。接下来,我们将解释颜色部分。ANSIEscapeSequenceANSIEscapeSequence也是随着终端的发展而发展的,不同设备的颜色规格也不同。比如早期的设备只支持3/4Bit,支持的颜色分别是8/16。大多数以ESC和“[”开头的ANSI转义序列嵌入在文本中,终端会查找并将其解释为命令,而不是字符串。ESC的ANSI值为27,八进制表示为\033,十六进制表示为\u001B。3/4位原始规格只有8/16种颜色。例如ESC[30;47m以ESC[开头,以m结尾,中间有代码,中间用分号隔开。颜色值为30-37,背景值为40-47。例如:echo-e"\u001B[31mhello"(如果要清除颜色,需要用ESC[39;49m(部分终端不支持)或ESC[0m)后来终端增加了90-的直接指定97和100-107“明亮”颜色功能。效果如下:下面是它的颜色对照表:8-bit后来因为256色在显卡上很常见,所以加了一个转义序列,从预定义的256色中选择,也就是说在原来的writingmethod添加了新的位来表示更多的颜色。ESC[38;5;m//设置字体颜色ESC[48;5;m//设置背景颜色0-7:standardcolors(asinESC[30–37m)8-15:highintensitycolors(asinESC[90–97m)16-231:6×6×6cube(216colors):16+36×r+6×g+b(0≤r,g,b≤5)232-255:grayscalefromblacktowhitein24steps支持更多颜色in终端,例如:echo-e"\u001B[38;5;11mhello"表示输出黄色字体。echo-e"\u001B[48;5;14;38;5;13mhello"表示输出蓝底粉红字体。下面是它的颜色对比表:24位及进一步发展是支持24位真彩色显卡,Xterm,KDE的Konsole,所有基于libvte的终端(包括GNOME终端)都支持24位前景色和背景色设置.ESC[38;2;;;m//前景色ESC[48;2;;;m//背景色例如:echo-e"\u001B[38;2;100;228;75mhello"输出的绿色字体代表rgb(100,228,75)。解析工具知道转义规范后,我们需要解析ANSI字符。既然规范比较多,我们先研究一下js中常用的颜色库来做个小小的探索。由于3/4bit兼容性较好,大部分工具(如粉笔)都会使用这8/16色进行高亮,所以我们先实现一个8/16色分析。这里引用了ansiparse解析库:核心思想是:constansiparse=require('ansiparse')constansiStr="\u001B[34mHello\u001B[39mWorld\u001B[31m!\u001B[39m"constjson=ansiparse(ansiStr)console.log(json)//json输出如下:[{foreground:'blue',text:'Hello'},{text:'World'},{foreground:'red',text:'!'}]那么我们就可以写一个函数,遍历上面解析出来的JSON数组,输出HTML。functioncreateHtml(ansiList,wrap=''){lethtml='';for(leti=0;i${value}`}functionbgCode(value,color){return`${value}`}functionsingleCode(value){return`${value}`}使用示例如下:conststr="\u001B[34mHello\u001B[39mWorld\u001B[31m!\u001B[39m";console.log(createHtml(parseAnsi(str)));//你好世界!部署实战有了上面的部分,我们就用一个简单的demo来实际演示一下部署日志吧!//项目目录结构demo|-package.json|-index.html|-webpack.config.js|-/src|-index.jsindex.jsbuild.sh我们在index.js中启动一个构建脚本来模拟我们真实的部署场景const{spawn}=require('child_process');constcmd=spawn('sh',['build.sh']);cmd.stdout.on('data',(data)=>{console.log(`stdout:${data}`);});cmd.stderr.on('data',(data)=>{console.log(`stderr:${data}`);});cmd.on('close',(code)=>{console.log(`childprocessexitedwithcode${code}`);});//build.shcddemonpxwebpack我们在终端试试,在控制台输入nodeindex.js,发现在输出日志中,我们没有看到对应的颜色,为什么child_process不能输出颜色,如果我们是在终端为什么可以直接输出颜色打包项目?为什么?第一反应是找源,也就是最常用的颜色输出库。以简单的方式为控制台的输出着色。https://github.com/Marak/colors.jshttps://github.com/chalk/chalk看了webpack-cli的源码,发现它使用colorette作为颜色输出库。那我们就来看看colorette的源码吧。在入口文件的开头,可以看到一个变量isColorSupported,用来判断是否支持彩色输出。https://github.com/jorgebucaran/colorette/blob/main/index.js#L17//colorette/index.jsimport*asttyfrom"tty"constenv=process.env||{}constargv=process.argv||[]constisDisabled="NO_COLOR"inenv||argv.includes("--no-color")constisForced="FORCE_COLOR"inenv||argv.includes("--color")constisWindows=process.platform==="win32"constisCompatibleTerminal=tty&&tty.isatty&&tty.isatty(1)&&env.TERM&&env.TERM!=="dumb"constisCI="CI"inenv&&("GITHUB_ACTIONS"inenv||"GITLAB_CI"inenv||"CIRCLECI"inenv)exportconstisColorSupported=!isDisabled&&(isForced||isWindows||isCompatibleTerminal||isCI)可以看到这个工具判断了很多条件来处理我们的输出流。只有以上条件成立,才会输出ANSI日志。在不满足以上条件的情况下,会切换更容易解析的输出方式。constisWindows=process.platform==="win32"参考:https://stackoverflow.com/questions/8683895/how-do-i-determine-the-current-operating-system-with-node-jsdumb:"dumb终端》哑终端是指不能执行一些特殊的ANSI转义序列如“删除行”、“清屏”或“控制光标位置”的计算机终端参考:https://zh.wikipedia.org/wiki/%E5%93%91%E7%BB%88%E7%AB%AF表示我们child_process的输出流已经关闭了终端模式(TTY),不满足以上四个条件。所以我们没有使用ANSI获得颜色日志。如何?我们可以通过显示传入的环境变量FORCE_COLOR=1或者带参数--color的命令强制启动颜色来解决这个问题。这样我们就得到了带有ANSI颜色信息的输出文本,最后解析得到HTML。

assetmain.js132bytes[comparedforemit][最小化](name:main)
./src/index.js289bytes[内置][codegenerated]
警告配置
The'mode'选项没有被设置,webpackwillfallbackto'production'forthisvalue。
将'mode'选项设置为'development'或'production'为每个环境启用默认值。
您也可以将其设置为“无”以禁用任何默认行为。了解更多:https://webpack.js.org/configuration/mode/
webpack5.53.0compiledwith1warningin201ms
然后我们就可以在浏览器中显示我们彩色输出的日志,与终端中的输出是一致的。参考https://www.twilio.com/blog/guide-node-js-logginghttps://github.com/jorgebucaran/colorette/blob/main/index.js#L17https://en.wikipedia.org/wiki/ANSI_escape_code#Colorshttps://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequenceshttps://stackoverflow.com/questions/15011478/ansi-questions-x1b25h-and-x1behttps:///bluesock.org/~willg/dev/ansi.htmlhttps://www.cnblogs.com/gamesky/archive/2012/07/28/2613264.htmlhttps://github.com/mmalecki/ansiparse