5

I am running a build, and I would like to be able to view the progress as it happens. But I would also like to save the output if the build has an error.

I know I can use Process.UseShellExecute = false, and RedirectStandardOutput, but that's only part of the story.

How can I do this?

Mechanical snail
  • 29,755
  • 14
  • 88
  • 113
user420667
  • 6,552
  • 15
  • 51
  • 83

3 Answers3

3

Maybe like this?

class Tee
{
    private readonly string m_programPath;
    private readonly string m_logPath;
    private TextWriter m_writer;

    public Tee(string programPath, string logPath)
    {
        m_programPath = programPath;
        m_logPath = logPath;
    }

    public void Run()
    {
        using (m_writer = new StreamWriter(m_logPath))
        {

            var process =
                new Process
                {
                    StartInfo =
                        new ProcessStartInfo(m_programPath)
                        { RedirectStandardOutput = true, UseShellExecute = false }
                };

            process.OutputDataReceived += OutputDataReceived;

            process.Start();
            process.BeginOutputReadLine();
            process.WaitForExit();
        }
    }

    private void OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        Console.WriteLine(e.Data);
        m_writer.WriteLine(e.Data);
    }
}
svick
  • 236,525
  • 50
  • 385
  • 514
2

Update

As Greg mentions in the comments below, MSBuild can write out to a log file while also outputting to console out of the box.

MSBuild [options] /filelogger /fileloggerparameters:LogFile=MSBuildLog.txt

Try the following simple C# program. It will take the redirected STDIN (Console.In) and write it to one or more files and STDOUT (Console.Out).

using System;
using System.Collections.Generic;
using System.IO;

namespace RedirectToFile
{
    class Program
    {
        static void Main(string[] args)
        {
            var buffer = new char[100];
            var outputs = new List<TextWriter>();

            foreach (var file in args)
                outputs.Add(new StreamWriter(file));

            outputs.Add(Console.Out);

            int bytesRead;
            do
            {
                bytesRead = Console.In.ReadBlock(buffer, 0, buffer.Length);
                outputs.ForEach(o => o.Write(buffer, 0, bytesRead));
            } while (bytesRead == buffer.Length);

            outputs.ForEach(o => o.Close());
        }
    }
}

I use it to redirect the output from an MSBuild batch file to disk whilst still outputting to the console window.

Usage: MSBuild [options] | RedirectToFile.exe MSBuildLog.txt
Dennis
  • 20,275
  • 4
  • 64
  • 80
  • `ReadBlock()` isn't required to always return the whole buffer full. You should check for `bytesRead > 0` instead. – svick Sep 09 '11 at 23:47
  • 1
    +1 this works pretty well, (despite it being somewhat spastic about how it prints to the screen) but unfortunately the colors from msbuild are lost. Any idea how to preserve those? – user420667 Sep 13 '11 at 17:12
  • 1
    Using the above program, there is no way to preserve the console output colours. If want additional logging from MSBuild have a look at the `msbuild.exe /logger` option, http://msdn.microsoft.com/en-us/library/ms171470.aspx – Dennis Sep 13 '11 at 20:32
  • 1
    MSBuild can write out to a log file while also outputting to console out of the box. `MSBuild [options] /filelogger /fileloggerparameters:LogFile=MSBuildLog.txt` – Graham Ambrose Oct 12 '12 at 08:30
1

this answer should help you Redirect Standard Output Efficiently in .NET

PS I am never sure if linking to another answer on SO is an answer or a comment

Community
  • 1
  • 1
Shaun Wilde
  • 8,228
  • 4
  • 36
  • 56