Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem capturing error output #117

Closed
mcartoixa opened this issue Apr 12, 2012 · 13 comments
Closed

Problem capturing error output #117

mcartoixa opened this issue Apr 12, 2012 · 13 comments

Comments

@mcartoixa
Copy link

I am currently trying to wrap the call to grunt in a custom MSBuild task so that it can integrate nicely in our (.NET based) continuous integration stack. Obviously, this is on WIndows.

The problem I have is that whenever there is an error in a grunt task (a jshint error for instance), my MSBuild task is not able to capture the errors for this task. Actually it seems I cannot have access to any output after (and including) the first error message.

I have been able to reproduce this behavior using a simple PowerShell command line:
powershell.exe -NonInteractive -NoLogo -ExecutionPolicy ByPass -Command "(node.exe grunt)" works fine every time, while powershell.exe -NonInteractive -NoLogo -ExecutionPolicy ByPass -Command "Write-Host (node.exe grunt)" eats every output after (and including) the first error (if any). The difference between these 2 command lines is that the first simply outputs the grunt output, while the second stores it in a temporary string then outputs it.

I don't really understand what is happening here, but my wild guess is that the grunt process may under certain conditions, somehow, terminate before all its output is done...

Also, as a side note: shouldn't errors be output on the stderr stream instead of the sdtout one?

@cowboy
Copy link
Member

cowboy commented Apr 12, 2012

I'm not sure what's going on here. Does it stop capturing on errors: >> Some error message, or warnings: <WARN> ... </WARN>?

The only thing I can think of is that when grunt.warn or grunt.fatal is called, \x07 is output which should cause the terminal to beep. I've filed #119 anyways, but I'm not sure it's related.

@mcartoixa
Copy link
Author

I've run the 2 command lines above on a project with jshint errors (adding the --no-color option). The outputs can be found here https://gist.github.com/2375042

OK messages are output fine.

@mcartoixa
Copy link
Author

Another note: using the --force option, I get to capture more, but not all, of the output.

@cowboy
Copy link
Member

cowboy commented Apr 14, 2012

I honestly have no idea what the problem might be. All the ERROR messages do differently than the OK messages is use red instead of green.

Does this happen for other tasks, or only for the lint task?

@mcartoixa
Copy link
Author

Sorry for the delay: it seems to happen to every task. I just used lint for convenience.

@ArturDorochowicz
Copy link

If I could add my 2cents, this is probably the infamous node.js problem with stdout/stderr being cut off non deterministically on Windows when piped. AFAIK, this happens to everything that runs in Node on Windows.

This works in cmd and powershell (output to the console): node.exe app.js
This works in cmd (redirection to file): node.exe app.js > file.txt
This fails in cmd and powershell (pipe into something): node.exe app.js | more
This fails in powershell (redirection to file): node.exe app.js > file.txt

The reason file redirection fails in powershell is that it's basically an alias for pipe into Out-File ...
I'm not sure why file redirection works in cmd, but in my tests it worked reliably.

There is probably like a ton of bugs logged for various node apps that has this as underlying cause, e.g. this one in mocha: mochajs/mocha#333

@cowboy
Copy link
Member

cowboy commented Apr 24, 2012

I'm going to close this issue as it doesn't seem to be anything I can handle internally in grunt. If you think of something I can do, please let me know.

@cowboy cowboy closed this as completed Apr 24, 2012
@Iristyle
Copy link

@mcartoixa @cowboy Did anyone ever find a reasonable solution for this?

Node 0.8.14
Grunt 0.4.0a latest

I have a Windows 2008 R2 server x86 (on EC2) as a Jenkins server. All of our builds are kicked off with Powershell.

The bootstrap script verifies Node, NPM, PhantomJS and Bower installations, then installs packages with NPM, followed by Bower, and finally Grunt.

This works great locally..

NPM, Bower and Grunt are all kicked off identically in the Powershell script. However, I'm only getting output from NPM and Bower in my output log on the build server.

I've gone as far as launching Node by hand, and redirecting the output to an event stream (in .NET), and trying to push that to the output that Jenkins is capturing, but no love at all. I'm really stumped with the behavior I'm 'seeing.

This is the hideous hack I've attempted under Jenkins. I get the word 'Initializing' from Grunt, and then that's it.

# MAJOR HACK to redirect node.exe output on Jenkins
$process = New-Object Diagnostics.Process
$process.StartInfo.FileName = $localNode
$gruntCli = Join-Path (Get-CurrentDirectory) '..\node_modules\grunt-cli\bin\grunt'
$gruntFile = Join-Path (Get-CurrentDirectory) '..\Gruntfile.js'
$process.StartInfo.Arguments = @($gruntCli, $cmdLine, '--gruntfile', $gruntFile, '--verbose', '--no-color')
$process.StartInfo.UseShellExecute = $false
$process.StartInfo.RedirectStandardOutput = $true
$process.StartInfo.RedirectStandardError = $true

@{SourceIdentifier = 'GruntOutput'; EventName = 'OutputDataReceived'},
@{SourceIdentifier = 'GruntError'; EventName = 'ErrorDataReceived'} |
  %{
    Unregister-Event -SourceIdentifier $_.SourceIdentifier `
      -ErrorAction SilentlyContinue
    Register-ObjectEvent -InputObject $process @_
  }
-
$process.Start() | Out-Null
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()

function Get-EventMessages([string[]]$names)
{
  $names |
    % { Get-Event -SourceIdentifier $_ -ErrorAction SilentlyContinue } |
    % {
      if ($_.SourceEventArgs.Data)
      {
        Write-Host $_.SourceEventArgs.Data
      }
      Remove-Event -EventIdentifier $_.EventIdentifier
    }
}

while (!$process.WaitForExit(100))
{
  Get-EventMessages -names 'GruntOutput', 'GruntError'
}

Start-Sleep -Seconds 1
Get-EventMessages -names 'GruntOutput', 'GruntError'
$process.Close()
if ($process.ExitCode -ne 0) { throw 'Build aborted! Grunt failed.'}

Note that the above does work fine on a local box as well... I'm just mystified here.

I'm leaning towards this being some sort of edge case with Jenkins -> Powershell -> Node.

I may try and pull Powershell out of the equation for the Grunt part, just to see what happens.

@Iristyle
Copy link

It looks like people are having similar issues with Mocha.
mochajs/mocha#333

@Iristyle
Copy link

I should also note that I seem to be getting the node exitcode, which I read in Powershell and report as a failure. It's just that the output is going off into space.

@Iristyle
Copy link

This is so wonky.. It seems that the issue is that Jenkins will only record the first console.log.

I took Powershell out of the equation and mimicked the Grunt cli script. Then I told Jenkins to run the Node script

var cwd = process.cwd()
//console.log('Working directory : ' + cwd);

//basically copied from node_modules/grunt_cli/bin/grunt script

// Nodejs libs.
var fs = require('fs');
var path = require('path');

// External libs.
var _dir = path.resolve(cwd, 'node_modules/grunt-cli/node_modules/lodash');
var _ = require(_dir);
var globdir = path.resolve(cwd, 'node_modules/grunt-cli/node_modules/glob');
var glob = require(globdir);

var gruntfile = path.resolve(cwd, 'Gruntfile.js');
var dir = path.resolve(gruntfile, '../node_modules/grunt');

// Run grunt.
var flushoutput = function() 
{
  while (process.stdout.bufferSize > 0) {
    process.stdout.once('drain', exit);
  }
  while (process.stderr.bufferSize > 0) {
    process.stderr.once('drain', exit);
  }
}
require(dir).tasks('default', {"color": false, "verbose": true }, flushoutput);

So when I run this, I only get the first line of Grunt

Initializing

If I uncomment the console.log for the cwd... I only get that line! I don't get Grunt output.

So for whatever reason, the only output that gets captured is the very first thing sent to console.log. So I'm not sure WTF is going on... not sure why I get complete Bower output...

But there is clearly an issue here with Node and stdout.

@Iristyle
Copy link

For anyone who might be following along, I also tried intercepting calls to process.stdout / process.stderr write ... and sending the strings to an array... so that I could make a single write call at the end. Couldn't get that working

So to recap, failures

  • Redirecting output in PS via .NET
  • Redirecting output inside a Node script

But I did finally find a solution if I drop down to cmd and execute this as part of my Jekins build steps.

del grunt-output.txt
node.exe node_modules\grunt-cli\bin\grunt default --verbose --no-color 2>&1 > grunt-output.txt
type grunt-output.txt

Soooooooo... hacky, redirecting stdout / stderr to a file like that, but it amazingly works. I was starting to go nuts because I couldn't repro this locally -- only happening under Jenkins.

Clearly less than ideal, but left as a work-around for posterity.

@thomaux
Copy link

thomaux commented Jul 11, 2013

Iristyle, just wanted to let you know I've used your approach and it solved the issues I was experiencing with the output being cut off. Thanks a bunch to explain what you have done to solve this issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants