demand

You want to see real-time output logs of log files/processes on the admin page. This is useful for scenarios where you cannot directly log in to the server using SSH, you do not have a good logging tool, or you simply want to check the output of the run

Train of thought

to

Use tail -f to get real-time file streams or pM2 logs to get output streams of the PM2 process. Consider adding a subscription ID to each stream so that multiple simultaneous subscriptions can be implemented

Go to the

When it comes to real-time on a Web page, websocket naturally comes to mind. The logic is not complicated. When a client sends a subscription ID, it links it to the data event of the stream corresponding to the ID, so that the data can be passed over

The core code

This article is mainly to give some practical ideas, so there will be no explanation of how socket. IO works

Generate flow

Run the child process using child_process.exec, which returns the stdout property as a readable stream:

const exec = require('child_process').exec; Const streams = {}; * @param file * @return id */ function watchFile(file) {return watchProcess(' tail -f ${file} '); } /** * custom command line, Pm2 logs 0 * @param CMD * @return id */ function watchProcess(CMD) {return watchStream(exec(CMD). } @param stream @return id */ function watchStream(stream) {const id = date.now (); streams[id] = stream; stream._buff = ''; Stream. on('data', data => {stream._buff += data; let lines = stream._buff.split('\n'); stream._buff = lines.pop(); lines.forEach(line => stream.emit('line', line)); }); }Copy the code

Bind the stream to the socket. IO subscription

const io = SocketIO(httpServer); io.on('connection', function (socket) { socket.on('sub', function (id) { if (! Streams [id]) return socket.emit('line', 'this subscription id does not exist: ${id}'); // Const pipe = line => socket.emit('line', ansiHTML(line)); // Const pipe = line => socket.emit('line', ansiHTML(line)); // Streams [id]. On ('line', pipe); }); });Copy the code

Front-end subscription ID

var socket = io.connect(); socket.on('line', function (data) { app.rawLines.push(data); if (app.rawLines.length > 2000) app.rawLines.splice(0, app.rawLines.length - 2000); }); socket.on('connect', function () { console.log('connect succeed'); socket.emit('sub', 'time'); // get a subscription id according to various business logic and subscribe});Copy the code

The front-end page uses VUE to render elements with very many lines, so the code is not pasted, and the final result is as follows

conclusion

This thing is close to webshell function, at least the output can be displayed, plus an input interface can be remote command execution, warning here allow remote command execution is very dangerous. The main idea is the idea, the code itself is not difficult, demo has been uploaded to Github, because it is demo, various error capture and recycling processing are not perfect, this also please study ~



Did this article help you? Welcome to join the front End learning Group wechat group: