无论是任务系统还是作业系统都会去执行linux命令或脚本,命令或脚本的输出也会实时展示在Web页面上,在终端中执行命令或脚本可以输出颜色,主要是因为这些有颜色的文字周围包含了颜色相关的ANSI码,例如:\033[31m运维咖啡吧\033[0m
如何在Web页面上输出时同样展示颜色呢,这里我用到了ansi_up.js
,ansi_up是一个简单易用的Javascript库,可将包含ANSI颜色转义码的文本转换为HTML。纯前端插件使用起来确实简单,只依赖一个js文件,示例代码如下:
<script src="../ansi_up.js" type="text/javascript"></script>
<script type="text/javascript">
var ansi_up = new AnsiUp;
var string = "\033[35m 运维咖啡吧 \033[0m"
var html = ansi_up.ansi_to_html(string);
$('#J_details').append(html);
</script>
这么使用一直没有问题,直到刚刚,小伙伴跟我说,执行了一个作业,日志输出到一半开始报错,之后前端页面直接卡死无法使用,简单排查就定位到了问题,这个作业是去一组主机上过滤日志文件输出错误日志,错误日志太多执行结果较大,不过也就2MB,ansi_up
性能有限已经无法渲染,问题定位到了,如何解决
我先是查了ansi_up
的文档,没有找到解决的方案,然后问了最懂程序员的AI搜索引擎,他给了我答案
修复ansi_up.js
这个难度太大,Jupyter
这个也不懂,但是xterm.js
我熟啊,之前在做webssh项目时就是通过xterm.js
来实现前后端的实时交互的。xterm是一个专业的前端终端组件,可以直接在浏览器中实现一个命令行终端应用,功能强大、配置复杂,但基本使用较为简单,示例代码如下:
<html>
<head>
<link href="/static/plugins/xterm/xterm.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="terminal"></div>
<script src="/static/plugins/xterm/xterm.js"></script>
<script>
var term = new Terminal();
term.open(document.getElementById('terminal'));
term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')
</script>
</body>
</html>
通过term.write
写数据,实际测试下来,一次性60MB的数据也能正常渲染,几十倍的性能提升,是真的强大。虽然这个问题解决了,渲染恢复了正常,但发现了更为严重的问题,作业执行过程中日志是先写入缓存的,日志输出太大会导致缓存被占满从而进程OOM,同时日志展示也不会分页,一次请求占用几十上百MB的内存,很快就导致系统OOM
日志输出太多实际上就失去了意义,根本也看不过来,由于大量的数据传输,前端体验也会变差,还提升了系统OOM的风险,限制日志输出大小似乎成了最好的解决方式,说干就干,代码比较简单
# 输出日志超过2M则强制结束
if len(old_log) > 2 * 1024 * 1024 or len(new_log) > 2 * 1024 * 1024:
details = '输出日志超大,当前作业已被系统强制结束'
判断下当前的日志记录大小以及新产生的日志大小是否超过2MB,如果超过则直接终止作业,同时提示用户调整
至此问题才算完全解决。我不禁在想,我们都喜欢自由,不设限制,但有些时候受限才是为了更自由