diff --git a/package.json b/package.json index dbaba350..537cd199 100644 --- a/package.json +++ b/package.json @@ -85,5 +85,8 @@ "transform-flow-strip-types", "transform-decorators-legacy" ] + }, + "optionalDependencies": { + "v8-profiler": "^5.7.0" } } diff --git a/servcmd.sh.js b/servcmd.sh.js index 37a7cd60..d47cac68 100755 --- a/servcmd.sh.js +++ b/servcmd.sh.js @@ -34,7 +34,7 @@ const SOCKETFILE = Config.get("service-socket.socket"); // Wipe the TTY process.stdout.write('\x1Bc'); -var commandline, eventlog, syslog; +var commandline, eventlog, syslog, errorlog; var client = net.createConnection(SOCKETFILE).on('connect', () => { commandline = readline.createInterface({ input: process.stdin, @@ -79,6 +79,11 @@ var client = net.createConnection(SOCKETFILE).on('connect', () => { console.log(data.toString().replace(/^(.+)$/mg, 'sys: $1')); }); + errorlog = spawn('tail', ['-f', 'error.log']); + errorlog.stdout.on('data', function (data) { + console.log(data.toString().replace(/^(.+)$/mg, 'error: $1')); + }); + }).on('data', (msg) => { msg = msg.toString(); diff --git a/src/main.js b/src/main.js index dbfc94cd..8b73e2e5 100644 --- a/src/main.js +++ b/src/main.js @@ -21,6 +21,8 @@ if (!Config.get('debug')) { }); } +let profileName = null; + // TODO: this can probably just be part of servsock.js // servsock should also be refactored to send replies instead of // relying solely on tailing logs @@ -78,6 +80,40 @@ function handleLine(line) { } } else if (line.indexOf('/reloadcert') === 0) { sv.reloadCertificateData(); + } else if (line.indexOf('/profile') === 0) { + try { + const fs = require('fs'); + const path = require('path'); + const profiler = require('v8-profiler'); + + if (profileName !== null) { + const filename = path.resolve( + __dirname, + '..', + `${profileName}.cpuprofile` + ); + const profile = profiler.stopProfiling(profileName); + profileName = null; + + const stream = profile.export(); + stream.on('error', error => { + LOGGER.error('Error exporting profile: %s', error); + profile.delete(); + }); + stream.on('finish', () => { + LOGGER.info('Exported profile to %s', filename); + profile.delete(); + }); + + stream.pipe(fs.createWriteStream(filename)); + } else { + profileName = `prof_${Date.now()}`; + profiler.startProfiling(profileName, true); + LOGGER.info('Started CPU profile'); + } + } catch (error) { + LOGGER.error('Unable to record CPU profile: %s', error); + } } }