2

I have a program that takes the Console output and writes it to a logfile, however it no longer shows up in the console window. Is there a way to keep it in the window but write it to the log file as well?

Update:

appLogStream = new FileStream(logFile, FileMode.Append, FileAccess.Write, FileShare.Read);
TextWriter logtxtWriter = Console.Out;
logstrmWriter = new StreamWriter(appLogStream);
if(!console) Console.SetOut(logstrmWriter);
logstrmWriter.AutoFlush = true;
Console.WriteLine("Started at " + DateTime.Now);

console is a constant set in the class. It basically tells it whether it is using the console window or not (readline is not called, etc, if not in console).

So is there a way to write to both the console and the file?

Arlen Beiler
  • 15,336
  • 34
  • 92
  • 135
  • Can you give more details on how you're sending console output to the file? Maybe a small code sample? – goric Jun 06 '12 at 16:22
  • BTW, if you using it for logging please instead consider using either built in logging infrastructure (or other libraries like Log4net). Consider reading on TraceListener and related classes to see how such 1-to-many output could be implemented and configured. – Alexei Levenkov Jun 06 '12 at 16:54
  • Is there some aspect of the environment you're working in that makes the approach you're using necessary, rather than using better solutions such as a central logger class or the .Net trace infrastructure? – hatchet - done with SOverflow Jun 06 '12 at 17:06

3 Answers3

2

You could simply read that stream log it and print it out.

It depends a little on your code if you assign the output stream to the inputstream of the outfile this could be a little harder if you read the content to a buffer that should be a little easier.


About your update I would suggest that you exchange all Console with a custom logging function e.g. a instance of MyLogger (code below) . Which writes your output to the console and to your log file.

class MyLogger {
    private FileStream appLogStream;

    public MyLogger() {
        appLogStream = new FileStream(logFile, FileMode.Append, FileAccess.Write,
                                      FileShare.Read);
        appLogStream.WriteLine("Started at " + DateTime.Now);
    }

    public Write(string msg) {
        Console.Write(msg);
        appLogStream.Write(msg);
    }

    public WriteLine(string msg) {
        Console.WriteLine(msg);
        appLogStream.WriteLine(msg);
    }
}
rekire
  • 47,260
  • 30
  • 167
  • 264
  • I think the problem is, once you call Console.SetOut, everything you write to Console goes to that writer, and not standard output. Your code above will likely just duplicate the output sent to appLogStream. – hatchet - done with SOverflow Jun 06 '12 at 16:43
  • 1
    +1. Essentially it is 1-to-many stream writer, For actual usage may be easier to have list of output writers and clone output to all of them. – Alexei Levenkov Jun 06 '12 at 16:50
  • @rekire - I agree that using a logger class is ideal. But his issue may be that he is working with an existing large code base that is already sprinkled all over with Console.Write... and he's trying to find an unobtrusive way to control where that all goes. – hatchet - done with SOverflow Jun 06 '12 at 17:04
  • Thankfully I was not using a large code base, so I just implemented this. I have one question. Can I use a constructor if the class is marked static? If so, when will it get fired? – Arlen Beiler Jun 09 '12 at 00:11
1

I think you can do something like this:

 public class ConsoleDecorator : TextWriter
{
    private TextWriter m_OriginalConsoleStream;

    public ConsoleDecorator(TextWriter consoleTextWriter)
    {
        m_OriginalConsoleStream = consoleTextWriter;
    }

    public override void WriteLine(string value)
    {
        m_OriginalConsoleStream.WriteLine(value);

        // Fire event here with value
    }


    public static void SetToConsole()
    {
        Console.SetOut(new ConsoleDecorator(Console.Out));
    }
}

You will have to "register" the wrapper with calling ConsoleDecorator.SetToConsole(); After that, every Console.WriteLine call will get to the custom method and there you can fire an event and get the text written in other places (logging for example).

if you will want to use that way, you will have to make the class a singleton and then you can have access to the even registration from other classes (which supposed to write to log file when the even is fired)

eyossi
  • 4,230
  • 22
  • 20
0

When you call Console.SetOut, you specify where Console should write to. If you don't (i.e. the way Console is typically used), and you call Console.Write, it checks if it has an output writer, and if not, sets it with

   stream = OpenStandardOutput(256);

and then

        Encoding encoding = Encoding.GetEncoding((int) Win32Native.GetConsoleOutputCP());
        writer = TextWriter.Synchronized(new StreamWriter(stream, encoding, 256, false) { HaveWrittenPreamble = true, AutoFlush = true });

So you should be able to do what you're doing now, and if you also want to echo everything to standard out as if you hadn't redirected Console, you can create your own writer using a stream you open yourself using Console.OpenStandardOutput method. The Win32Native used in that code is internal, so you don't have access to it, but you can use the Console.OutputEncoding to retrieve the encoding that it's using.

Something you can also try is using the Console.Out property to get and hang onto the standard output TextWriter just before you call SetOut. Then you can just use that to echo to standard output.