From 69285c7a79e1b6c1c0748f18a9cd41cbd4958098 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Sun, 4 Nov 2012 22:11:55 -0800 Subject: [PATCH] issue #54: fix stderr flushing of dtrace child proc (again) --- CHANGES.md | 4 +++- bin/bunyan | 46 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 776ab71..7974454 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,9 @@ ## bunyan 0.16.4 (not yet released) -(nothing yet) +- issue #54: Ensure (again, see 0.16.2) that stderr from the dtrace child + process (when using `bunyan -p PID`) gets through. There had been a race + between exiting bunyan and the flushing of the dtrace process' stderr. ## bunyan 0.16.3 diff --git a/bin/bunyan b/bin/bunyan index 8b1d872..ef31200 100755 --- a/bin/bunyan +++ b/bin/bunyan @@ -15,6 +15,8 @@ var fs = require('fs'); var warn = console.warn; var spawn = require('child_process').spawn; +var nodeSpawnSupportsStdio = (Number(process.version.split('.')[1]) >= 8); + //---- globals and constants @@ -907,13 +909,19 @@ function processPid(opts, stylize, callback) { var leftover = ""; // Left-over partial line from last chunk. var argv = ['dtrace', '-Z', '-x', 'strsize=4k', '-qn', format('bunyan%d:::log-*{printf("%s", copyinstr(arg0))}', opts.pid)]; - var dtrace = spawn(argv[0], argv.slice(1)); - child = dtrace; // intentionall global + var dtrace = spawn(argv[0], argv.slice(1), + // Share the stderr handle to have error output come + // straight through. Only supported in v0.8+. + {stdio: ['pipe', 'pipe', process.stderr]}); + child = dtrace; // intentionally global - dtrace.stderr.setEncoding('utf8'); - dtrace.stderr.on('data', function (chunk) { - process.stderr.write(chunk); - }); + function finish(code) { + if (leftover) { + handleLogLine(null, leftover, opts, stylize); + leftover = ''; + } + callback(returnCode); + } dtrace.stdout.setEncoding('utf8'); dtrace.stdout.on('data', function (chunk) { @@ -932,13 +940,27 @@ function processPid(opts, stylize, callback) { handleLogLine(null, lines[i], opts, stylize); } }); - dtrace.on('exit', function (code) { - if (leftover) { - handleLogLine(null, leftover, opts, stylize); - leftover = ''; + + if (nodeSpawnSupportsStdio) { + dtrace.on('exit', finish); + } else { + // Fallback (for < v0.8) to pipe the dtrace process' stderr to this stderr. + // Wait for all of (1) process 'exit', (2) stderr 'end', and (2) stdout + // 'end' before returning to ensure all stderr is flushed (issue #54). + var returnCode = null; + var eventsRemaining = 3; + function countdownToFinish(code) { + returnCode = code; + eventsRemaining--; + if (eventsRemaining == 0) { + finish(returnCode); + } } - callback(code); - }); + dtrace.stderr.pipe(process.stderr); + dtrace.stderr.on('end', countdownToFinish); + dtrace.stderr.on('end', countdownToFinish); + dtrace.on('exit', countdownToFinish); + } }