In a C# console application, is there a smart way to have console output mirrored to a text file?
Currently I am just passing the same string to both Console.WriteLine and InstanceOfStreamWriter.WriteLine in a log method.
In a C# console application, is there a smart way to have console output mirrored to a text file?
Currently I am just passing the same string to both Console.WriteLine and InstanceOfStreamWriter.WriteLine in a log method.
This may be some kind of more work, but I would go the other way round.
Instantiate a TraceListener for the console and one for the log file; thereafter use Trace.Write statements in your code instead of Console.Write. It becomes easier afterwards to remove the log, or the console output, or to attach another logging mechanism.
static void Main(string[] args)
{
Trace.Listeners.Clear();
TextWriterTraceListener twtl = new TextWriterTraceListener(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName));
twtl.Name = "TextLogger";
twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;
ConsoleTraceListener ctl = new ConsoleTraceListener(false);
ctl.TraceOutputOptions = TraceOptions.DateTime;
Trace.Listeners.Add(twtl);
Trace.Listeners.Add(ctl);
Trace.AutoFlush = true;
Trace.WriteLine("The first line to be in the logfile and on the console.");
}
As far as I can recall, you can define the listeners in the application configuration making it possible to activate or deactivate the logging without touching the build.
Check out log4net. With log4net you can set up console and file appenders that will can output log messages to both places with a single log statement.
Can't you just redirect the output to a file, using the > command?
c:\>Console.exe > c:/temp/output.txt
If you need to mirror, you can try find a win32 version of tee that splits the output to a file.
See https://superuser.com/questions/74127/tee-for-windows to run tee from PowerShell
You could subclass the TextWriter class, and then assign its instance to the Console.Out using the Console.SetOut method - which in particular does the same thing as passing the same string to both methods in the log method.
Another way might declaring your own Console class and use the using statement to distinguish between the classes:
using Console = My.Very.Own.Little.Console;
To access the standard console you'd then need:
global::Console.Whatever
Log4net can do this for you. You would only write something like this:
logger.info("Message");
A configuration will determine whether the print out will go to console, file or both.
My answer is based on the most-voted non-accepted answer, and also the least-voted answer which I think is the most elegant solution so far. It's a little more generic in terms of the stream type you can use (you may use a MemoryStream for instance), but I've omitted all the extended functionality included in the latter answer for brevity.
class ConsoleMirrorWriter : TextWriter
{
private readonly StreamWriter _writer;
private readonly TextWriter _consoleOut;
public ConsoleMirrorWriter(Stream stream)
{
_writer = new StreamWriter(stream);
_consoleOut = Console.Out;
Console.SetOut(this);
}
public override Encoding Encoding => _writer.Encoding;
public override void Flush()
{
_writer.Flush();
_consoleOut.Flush();
}
public override void Write(char value)
{
_writer.Write(value);
_consoleOut.Write(value);
}
protected override void Dispose(bool disposing)
{
if (!disposing) return;
_writer.Dispose();
Console.SetOut(_consoleOut);
}
}
Usage:
using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName)))
using (var writer = new ConsoleMirrorWriter(stream))
{
// Code using console output.
}