Redirecting standard output using the -logFile parameter when in batchmode

It does redirect to stdout, but as documentation says, stdout on Windows for GUI applications is not the console. Console is stdout for console applications, and as you observe, if you capture stdout from Unity in a standard application, and then write it to console, it appears just fine (which proves that Unity does output to stdout).

This is not exactly accurate. A Windows GUI process, will, by default, not inherit stdout handles, but the important caveat here is that they can, and more importantly, it should. It is absolutely be Unity’s job to use these available APIs to redirect stdout correctly and have a functioning build system. You have a command that is expected to be used from the console, it should be expected to behave like a console app. It doesn’t matter that it’s running a GUI behind the scenes, it’s your job to figure out the correct APIs to use and fix this objectively broken behavior. This is why Windows API exposes these process flags.

The handle inheritance is set up by whatever launches a process, not the process itself. If whatever launches Unity makes it inherit stdout handle, then Unity will happily use it (as https://discussions.unity.com/t/622567/20 shows). Cmd.exe doesn’t set up stdout inheritance for GUI programs and that’s why you don’t see it there.

By the way, Unity 2023.1 contains a second executable (unity.com) that’s compiled as a console application, which will make cmd.exe pass stdout to Unity correctly. So you can now invoke that instead of you want it to run synchronously through cmd.exe.

1 Like

Is documentation available anywhere for this functionality?

I am interested but encountering some issues and can’t find any documentation actually detailing what’s going on here.

Thanks

What issues are you seeing?

I’ve redirected my pointer from the .exe to the .com, trying with and without -logfile, and I’m getting what appears to be a total activity freeze.

No response, no output, nothing.

Our existing pipeline is running through Powershell Start-Process, so I’m wondering if that has something to do with it, but at the moment I haven’t been able to test that yet.

Are you able to capture the dump of the process through task manager when it freezes? Does it only happen via .com and not .exe?

The .exe works and outputs to the output log file in realtime. Had no issues.

This is the code;

Start-Process -FilePath $unity -Wait -NoNewWindow -ArgumentList `
"-batchmode", `
"-quit", `
"-projectPath $unityProjectPath", `
"-logfile $unityLogFile", `
"-buildWindowsPlayer $clientBuildDestination"

When I redirected it towards the .com I removed the -logfile argument, trying both -logfile ` and no argument at all.

I’ll try and capture a dump for you now, the tricky thing is that I’m not getting any visible errors at all. It just sort of goes into some kind of standby like nothing is happening and no output is being redirected.

I imagine there may be something I’m missing here, but I’m not sure what.

Edit:

Further investigation leads me to believe that Unity is indeed finishing compiling and completing the builds.

However, not only is my implementation not reading back to the console, but the console doesn’t receive a completion record and as such gets stuck at that part of the script while it endlessly waits for one.

Try using “-logfile -”. That will make Unity output to stdout.

@Tautvydas-Zilys We want to log our logs to file but log some specific messages to console in Linux. We want to log specific messages to console like FPS statistiscs etc.

Currently we use “-nographics -logFile game_server.log” as parameter and we want to keep this while only outputting statistics to console in Linux. Is there any way to accomplish this?

That’d be pretty hard, -logFile argument quite literally overrides the stdout handle in order to capture everything in the log file.

Hey, this has worked for the most part now.

Output is being correct passed back to Powershell, however—now it forcefully closes the powershell instance when it returns rather than allowing it to continue executing.

I’ve tried -Wait and also $process.WaitForExit() with -Passthru neither of which work as expected.

Using -NoNewWindow is also mandatory since otherwise it flashes a cmd on the screen for half a second and then forcefully closes the cmd and the powershell.

So far, this is the currently working code with the unexpected application exit.

$unityBuildProcess = Start-Process -FilePath $unity -NoNewWindow -PassThru -ArgumentList `
    "-batchmode", `
    "-quit", `
    "-projectPath $unityProjectPath", `
    "-logFile -", `
    "-buildWindowsPlayer $clientBuildDestination"

$unityBuildProcess.WaitForExit()

Read-Host -prompt "`nFinished! Press any key to exit...`n"

The Read-Host following will never execute.

That is weird, we don’t really interact with the parent process. Does the same thing happen if you start Unity from cmd.exe?

Just wanted to share our final setup here, for Unity 2023.2. This runs in Powershell, and we have it wrapped up in a Run-Unity commandlet.

& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\editor\Unity.exe" -batchmode -disable-assembly-updater -silent-crashes -logFile - $AdditionalArguments | Write-Output

This will stream output from Unity as the output handle of the commandlet, meaning you can pipe it around as normal in Powershell.

A few notes:

  • The -logFile - is necessary, otherwise it will suppress all output.
  • The | Write-Output is required because it redirects the stdout handle to the output of the script.
  • You must use Write-Output, not Write-Host or Write-Default, both of which write to the host console, not the stdout of the command.

Alternatively, you can remove the Write-Output if you execute editor\Unity.com instead of editor\Unity.exe. However, we’ve chosen not to do that, given that the console build is undocumented, and I’m not sure what lies in wait there.

1 Like