├── .gitignore ├── README.md ├── index.html ├── index.js ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inline log 2 | 3 | I wrote a tiny (potentially naff) logger thing that captures all `stdout` and `stderr` and logs in realtime to the browser (using server sent events). 4 | 5 | Kinda inspired by the way [Zeit's now](https://zeit.co/now) shows you a loading screen during deployment, but I wanted to get at the stdout logging on my now instances (since you don't have this functionality at the moment). 6 | 7 | ## Install 8 | 9 | Firslty get the module: `npm i -S inline-log`, then in your http server (I'm using Express below): 10 | 11 | ```js 12 | app.use('/_logger', require('inline-log')({ limit: 50 })) 13 | ``` 14 | 15 | That'll capture all the stdout/err and when you visit http://my-site.com/_logger it'll put your logs on the screen (with the last 50 lines). Obviously you can add auth or stuff before the middleware too. 16 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | _log 5 | 6 | 70 | 71 | 72 | 73 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const intercept = require('intercept-stdout'); 2 | const localLogger = require('fs').readFileSync(__dirname + '/index.html', 'utf8'); 3 | let connections = []; 4 | let id = 0; 5 | const log = []; 6 | 7 | module.exports = ({ limit = 50 } = {}) => { 8 | unhook = intercept( 9 | captureLog.bind(null, 'stdout', limit), 10 | captureLog.bind(null, 'stderr', limit) 11 | ); 12 | return logger; 13 | }; 14 | 15 | function captureLog(type, limit, txt) { 16 | id++; 17 | const data = { txt, id, timestamp: new Date().toJSON(), type }; 18 | log.push(data); 19 | connections = connections.filter(res => { 20 | if (res.connection.writable) { 21 | res.write(`data: ${JSON.stringify(data)}\neventId:${id}\n\n`); 22 | return true; 23 | } 24 | 25 | try { 26 | res.close(); 27 | } catch (e) {}; 28 | 29 | return false; 30 | }); 31 | 32 | log.splice(0, log.length - limit); 33 | } 34 | 35 | function logger(req, res, next) { 36 | if (req.headers.accept !== 'text/event-stream') { 37 | // send the HTML page instead 38 | res.writeHead(200, { 'content-type': 'text/html' }); 39 | res.end(localLogger); 40 | return; 41 | } 42 | // req.socket.setTimeout(Infinity); 43 | res.writeHead(200, { 44 | 'content-type': 'text/event-stream', 45 | 'cache-control': 'no-cache', 46 | 'connection': 'keep-alive', 47 | 'x-accel-buffering': 'no', 48 | 'transfer-encoding': '', 49 | }); 50 | 51 | let offset = parseInt(req.headers['Last-Event-ID'], 10) || 0; 52 | 53 | // flush 54 | res.write('\n'.repeat(2048)); 55 | 56 | log.forEach(log => { 57 | if (log.id > offset) { 58 | res.write(`data: ${JSON.stringify(log)}\neventId:${log.id}\n\n`); 59 | } 60 | }); 61 | 62 | connections.push(res); 63 | } 64 | 65 | setInterval(() => { 66 | connections = connections.filter(res => { 67 | if (res.connection.writable) { 68 | res.write(`eventId:${id}\n\n`); 69 | return true; 70 | } 71 | 72 | try { 73 | res.close(); 74 | } catch (e) {}; 75 | 76 | return false; 77 | }); 78 | }, 1000); 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inline-log", 3 | "version": "1.0.5", 4 | "description": "Middleware logger that captures STDOUT + STDERR", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "Remy Sharp", 11 | "license": "MIT", 12 | "dependencies": { 13 | "intercept-stdout": "^0.1.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | intercept-stdout: 4 | version "0.1.2" 5 | resolved "https://registry.yarnpkg.com/intercept-stdout/-/intercept-stdout-0.1.2.tgz#126abf1fae6c509a428a98c61a631559042ae9fd" 6 | dependencies: 7 | lodash.toarray "^3.0.0" 8 | 9 | lodash._arraycopy@^3.0.0: 10 | version "3.0.0" 11 | resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" 12 | 13 | lodash._basevalues@^3.0.0: 14 | version "3.0.0" 15 | resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" 16 | 17 | lodash._getnative@^3.0.0: 18 | version "3.9.1" 19 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 20 | 21 | lodash.isarguments@^3.0.0: 22 | version "3.1.0" 23 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 24 | 25 | lodash.isarray@^3.0.0: 26 | version "3.0.4" 27 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 28 | 29 | lodash.keys@^3.0.0: 30 | version "3.1.2" 31 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 32 | dependencies: 33 | lodash._getnative "^3.0.0" 34 | lodash.isarguments "^3.0.0" 35 | lodash.isarray "^3.0.0" 36 | 37 | lodash.toarray@^3.0.0: 38 | version "3.0.2" 39 | resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-3.0.2.tgz#2b204f0fa4f51c285c6f00c81d1cea5a23041179" 40 | dependencies: 41 | lodash._arraycopy "^3.0.0" 42 | lodash._basevalues "^3.0.0" 43 | lodash.keys "^3.0.0" 44 | 45 | --------------------------------------------------------------------------------