Esto puede ser algo más trabajo, pero yo iría al revés.
Cree una instancia TraceListener
para la consola y otra para el archivo de registro; a partir de entonces, use Trace.Write
declaraciones en su código en lugar de Console.Write
. Posteriormente, resulta más fácil eliminar el registro o la salida de la consola, o adjuntar otro mecanismo de registro.
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.");
}
Por lo que puedo recordar, puede definir los oyentes en la configuración de la aplicación, lo que permite activar o desactivar el registro sin tocar la compilación.
Esta es una clase simple que subclasifica TextWriter para permitir la redirección de la entrada tanto a un archivo como a la consola.
Úselo así
using (var cc = new ConsoleCopy("mylogfile.txt")) { Console.WriteLine("testing 1-2-3"); Console.WriteLine("testing 4-5-6"); Console.ReadKey(); }
Aquí está la clase:
class ConsoleCopy : IDisposable { FileStream fileStream; StreamWriter fileWriter; TextWriter doubleWriter; TextWriter oldOut; class DoubleWriter : TextWriter { TextWriter one; TextWriter two; public DoubleWriter(TextWriter one, TextWriter two) { this.one = one; this.two = two; } public override Encoding Encoding { get { return one.Encoding; } } public override void Flush() { one.Flush(); two.Flush(); } public override void Write(char value) { one.Write(value); two.Write(value); } } public ConsoleCopy(string path) { oldOut = Console.Out; try { fileStream = File.Create(path); fileWriter = new StreamWriter(fileStream); fileWriter.AutoFlush = true; doubleWriter = new DoubleWriter(fileWriter, oldOut); } catch (Exception e) { Console.WriteLine("Cannot open file for writing"); Console.WriteLine(e.Message); return; } Console.SetOut(doubleWriter); } public void Dispose() { Console.SetOut(oldOut); if (fileWriter != null) { fileWriter.Flush(); fileWriter.Close(); fileWriter = null; } if (fileStream != null) { fileStream.Close(); fileStream = null; } } }
fuente
Console.WriteLine()
, que era exactamente lo que quería.Console.SetOut(doubleWriter);
. Lo que es modificar un global para Console, me tomó un poco, ya que estoy tan acostumbrado a trabajar en aplicaciones donde prácticamente nada es global. ¡Buen material!Consulte log4net . Con log4net puede configurar la consola y los anexos de archivos que pueden enviar mensajes de registro a ambos lugares con una sola declaración de registro.
fuente
¿No puede simplemente redirigir la salida a un archivo, usando el
>
comando?Si necesita duplicar, puede intentar encontrar una versión win32
tee
que divida la salida en un archivo.Consulte /superuser/74127/tee-for-windows para ejecutar tee desde PowerShell
fuente
Puede subclasificar la clase TextWriter y luego asignar su instancia a Console.Out usando el método Console.SetOut , que en particular hace lo mismo que pasar la misma cadena a ambos métodos en el método de registro.
Otra forma podría declarar su propia clase de consola y usar la declaración using para distinguir entre las clases:
using Console = My.Very.Own.Little.Console;
Para acceder a la consola estándar, necesitaría:
global::Console.Whatever
fuente
EDITAR: Este método brinda la posibilidad de redirigir la información de la consola proveniente de un paquete de terceros. anular el método WriteLine es bueno para mi situación, pero es posible que deba anular otros métodos de escritura dependiendo del paquete de terceros.
Primero necesitamos crear una nueva clase inherente a StreamWriter, digamos CombinedWriter;
Luego inicie un nuevo instante de CombinedWriter con Console.Out;
Finalmente, podemos redirigir la salida de la consola al instante de la nueva clase mediante Console.SetOut;
El siguiente código es la nueva clase que funciona para mí.
public class CombinedWriter : StreamWriter { TextWriter console; public CombinedWriter(string path, bool append, Encoding encoding, int bufferSize, TextWriter console) :base(path, append, encoding, bufferSize) { this.console = console; base.AutoFlush = true; // thanks for @konoplinovich reminding } public override void WriteLine(string value) { console.Write(value); base.WriteLine(value); } }
fuente
public override void Write(char value);
,public override void Write(char[] buffer);
,public override void Write(string value);
ypublic override void Write(char[] buffer, int index, int count);
. De lo contrario, no se imprime en la consola si usa elWriteLine(format, ...)
método.Log4net puede hacer esto por usted. Solo escribirías algo como esto:
logger.info("Message");
Una configuración determinará si la impresión se enviará a la consola, al archivo oa ambos.
fuente
Creo que lo que ya está utilizando es el mejor enfoque. Un método simple para reflejar esencialmente su salida.
Primero declare un TextWriter global al principio:
private TextWriter txtMirror = new StreamWriter("mirror.txt");
Luego crea un método para escribir:
// Write empty line private void Log() { Console.WriteLine(); txtMirror.WriteLine(); } // Write text private void Log(string strText) { Console.WriteLine(strText); txtMirror.WriteLine(strText); }
Ahora, en lugar de usar
Console.WriteLine("...");
, useLog("...");
. Simple como eso. ¡Es aún más corto!Podría haber algún problema si cambia la posición del cursor (
Console.SetCursorPosition(x, y);
), pero por lo demás funciona bien, ¡yo también lo uso!EDITAR
Por supuesto, puede crear un método de
Console.Write();
la misma manera si no está usando solo WriteLinesfuente
Como sugirió Arul, el uso
Console.SetOut
se puede usar para redirigir la salida a un archivo de texto:Console.SetOut(new StreamWriter("Output.txt"));
fuente
La decisión de usar una clase, heredada de StreamWriter, sugerencias del usuario Keep Thinking, funciona. Pero tuve que agregar a la base del constructor.AutoFlush = true:
{ this.console = console; base.AutoFlush = true; }
y una llamada explícita al destructor:
public new void Dispose () { base.Dispose (); }
De lo contrario, el archivo se cierra antes de que haya registrado todos los datos.
Lo estoy usando como:
CombinedWriter cw = new CombinedWriter ( "out.txt", true, Encoding.Unicode, 512, Console.Out ); Console.SetOut (cw);
fuente
¡Gracias a Keep Thinking por la excelente solución! Agregué algunas anulaciones adicionales para evitar registrar ciertos eventos de escritura de la consola que (para mis propósitos) solo se esperan para la visualización de la consola.
using System; using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; namespace RedirectOutput { public class CombinedWriter : StreamWriter { TextWriter console; public CombinedWriter(string path, bool append, TextWriter consoleout) : base(path, append) { this.console = consoleout; base.AutoFlush = true; } public override void Write(string value) { console.Write(value); //base.Write(value);//do not log writes without line ends as these are only for console display } public override void WriteLine() { console.WriteLine(); //base.WriteLine();//do not log empty writes as these are only for advancing console display } public override void WriteLine(string value) { console.WriteLine(value); if (value != "") { base.WriteLine(value); } } public new void Dispose() { base.Dispose(); } } class Program { static void Main(string[] args) { CombinedWriter cw = new CombinedWriter("combined.log", false, Console.Out); Console.SetOut(cw); Console.WriteLine("Line 1"); Console.WriteLine(); Console.WriteLine("Line 2"); Console.WriteLine(""); for (int i = 0; i < 10; i++) { Console.Write("Waiting " + i.ToString()); Console.CursorLeft = 0; } Console.WriteLine(); for (int i = 0; i < 10; i++) { Console.Write("Waiting " + i.ToString()); } Console.WriteLine(); Console.WriteLine("Line 3"); cw.Dispose(); } } }
fuente
Si duplica la salida de la consola de un código que no controla, por ejemplo, una biblioteca de terceros, todos los miembros de TextWriter deben sobrescribirse. El código usa ideas de este hilo.
Uso:
using (StreamWriter writer = new StreamWriter(filePath)) { using (new ConsoleMirroring(writer)) { // code using console output } }
ConsoleMirroring clase
public class ConsoleMirroring : TextWriter { private TextWriter _consoleOutput; private TextWriter _consoleError; private StreamWriter _streamWriter; public ConsoleMirroring(StreamWriter streamWriter) { this._streamWriter = streamWriter; _consoleOutput = Console.Out; _consoleError = Console.Error; Console.SetOut(this); Console.SetError(this); } public override Encoding Encoding { get { return _consoleOutput.Encoding; } } public override IFormatProvider FormatProvider { get { return _consoleOutput.FormatProvider; } } public override string NewLine { get { return _consoleOutput.NewLine; } set { _consoleOutput.NewLine = value; } } public override void Close() { _consoleOutput.Close(); _streamWriter.Close(); } public override void Flush() { _consoleOutput.Flush(); _streamWriter.Flush(); } public override void Write(double value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(string value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(object value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(decimal value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(float value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(bool value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(int value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(uint value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(ulong value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(long value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(char[] buffer) { _consoleOutput.Write(buffer); _streamWriter.Write(buffer); } public override void Write(char value) { _consoleOutput.Write(value); _streamWriter.Write(value); } public override void Write(string format, params object[] arg) { _consoleOutput.Write(format, arg); _streamWriter.Write(format, arg); } public override void Write(string format, object arg0) { _consoleOutput.Write(format, arg0); _streamWriter.Write(format, arg0); } public override void Write(string format, object arg0, object arg1) { _consoleOutput.Write(format, arg0, arg1); _streamWriter.Write(format, arg0, arg1); } public override void Write(char[] buffer, int index, int count) { _consoleOutput.Write(buffer, index, count); _streamWriter.Write(buffer, index, count); } public override void Write(string format, object arg0, object arg1, object arg2) { _consoleOutput.Write(format, arg0, arg1, arg2); _streamWriter.Write(format, arg0, arg1, arg2); } public override void WriteLine() { _consoleOutput.WriteLine(); _streamWriter.WriteLine(); } public override void WriteLine(double value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(decimal value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(string value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(object value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(float value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(bool value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(uint value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(long value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(ulong value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(int value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(char[] buffer) { _consoleOutput.WriteLine(buffer); _streamWriter.WriteLine(buffer); } public override void WriteLine(char value) { _consoleOutput.WriteLine(value); _streamWriter.WriteLine(value); } public override void WriteLine(string format, params object[] arg) { _consoleOutput.WriteLine(format, arg); _streamWriter.WriteLine(format, arg); } public override void WriteLine(string format, object arg0) { _consoleOutput.WriteLine(format, arg0); _streamWriter.WriteLine(format, arg0); } public override void WriteLine(string format, object arg0, object arg1) { _consoleOutput.WriteLine(format, arg0, arg1); _streamWriter.WriteLine(format, arg0, arg1); } public override void WriteLine(char[] buffer, int index, int count) { _consoleOutput.WriteLine(buffer, index, count); _streamWriter.WriteLine(buffer, index, count); } public override void WriteLine(string format, object arg0, object arg1, object arg2) { _consoleOutput.WriteLine(format, arg0, arg1, arg2); _streamWriter.WriteLine(format, arg0, arg1, arg2); } protected override void Dispose(bool disposing) { if (disposing) { Console.SetOut(_consoleOutput); Console.SetError(_consoleError); } } }
fuente
En realidad, puede crear un reflejo transparente de Console.Out to Trace implementando su propia clase heredada de TextWriter y anulando el método WriteLine.
En WriteLine puede escribirlo en Trace, que luego se puede configurar para escribir en un archivo.
Encontré esta respuesta muy útil: https://stackoverflow.com/a/10918320/379132
¡Realmente funcionó para mí!
fuente
Mi respuesta se basa en la respuesta no aceptada más votada , y también en la respuesta menos votada, que creo que es la solución más elegante hasta ahora. Es un poco más genérico en términos del tipo de flujo que puede usar (puede usar,
MemoryStream
por ejemplo), pero he omitido toda la funcionalidad extendida incluida en la última respuesta por brevedad.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); } }
Uso:
using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName))) using (var writer = new ConsoleMirrorWriter(stream)) { // Code using console output. }
fuente