Skip to content

Instantly share code, notes, and snippets.

@msugakov
Created April 27, 2014 19:13
Show Gist options
  • Save msugakov/11353282 to your computer and use it in GitHub Desktop.
Save msugakov/11353282 to your computer and use it in GitHub Desktop.
C# program that starts process and combines its standart output and standard error in one stream
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
class App
{
public static int ExecuteProcess(
string fileName,
string arguments,
int timeout,
out string combinedOutput)
{
int exitCode;
using (var process = new Process())
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.Start();
using (var combinedStream = new StringWriter())
using (Task<bool> processWaiter = Task.Factory.StartNew(() => process.WaitForExit(timeout)))
using (Task outputReader = Task.Factory.StartNew((Action<object>)AppendLinesFunc, Tuple.Create(combinedStream, "stdout", process.StandardOutput)))
using (Task errorReader = Task.Factory.StartNew((Action<object>)AppendLinesFunc, Tuple.Create(combinedStream, "stderr", process.StandardError)))
{
bool waitResult = processWaiter.Result;
if (!waitResult)
{
process.Kill();
}
Task.WaitAll(outputReader, errorReader);
if (!waitResult)
{
throw new TimeoutException("Process wait timeout expired");
}
exitCode = process.ExitCode;
combinedOutput = combinedStream.ToString();
}
}
return exitCode;
}
private static void AppendLinesFunc(object packedParams)
{
// Unpack params from tuple object
var paramsTuple = (Tuple<StringWriter, string, StreamReader>)packedParams;
StringWriter writer = paramsTuple.Item1;
string marker = paramsTuple.Item2;
StreamReader reader = paramsTuple.Item3;
// Collect output from reader
string line;
while ((line = reader.ReadLine()) != null)
{
// Append to writer is critical section in order to prevent concurrent
// writes from stdout and stderr to interfere with each other.
lock (writer)
{
writer.WriteLine("{0} {1}: {2}", marker, DateTime.Now, line);
}
}
}
private static void Main(string[] args)
{
string output;
int timeout = 10 * 1000; // ten seconds
int exitCode = ExecuteProcess(args[0], args.Length > 1 ? args[1] : null, timeout, out output);
Console.WriteLine("Exit code: {0}", exitCode);
Console.WriteLine("Combined output:\n{0}", output);
}
}
using System;
class App
{
static void Main()
{
var random = new Random();
int n = 10;
for (int i = 0; i < n; ++i)
{
int v = random.Next();
if (v % 2 == 0)
{
Console.Out.WriteLine("even number - {0}", v);
}
else
{
Console.Error.WriteLine("odd number - {0}", v);
}
}
}
}
Compile a.cs and b.cs with commands:
csc.exe a.cs
csc.exe b.cs
Run with:
a.exe b.exe
Sample output:
D:\tmp>a.exe b.exe
Exit code: 0
Combined output:
stderr 27.04.2014 21:09:57: odd number - 1519580101
stdout 27.04.2014 21:09:57: even number - 900702068
stdout 27.04.2014 21:09:57: even number - 1576951340
stdout 27.04.2014 21:09:57: even number - 1966632972
stderr 27.04.2014 21:09:57: odd number - 854441047
stderr 27.04.2014 21:09:57: odd number - 1356825953
stderr 27.04.2014 21:09:57: odd number - 64614431
stderr 27.04.2014 21:09:57: odd number - 713766487
stderr 27.04.2014 21:09:57: odd number - 1509132475
stderr 27.04.2014 21:09:57: odd number - 1756029823
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment