콘솔 출력을 파일로 미러링


88

C # 콘솔 애플리케이션에서 콘솔 출력을 텍스트 파일에 미러링하는 현명한 방법이 있습니까?

현재 저는 로그 메서드 Console.WriteLine와 둘 다에 동일한 문자열을 전달하고 InstanceOfStreamWriter.WriteLine있습니다.

답변:


118

이것은 좀 더 많은 일이 될 수 있지만 나는 다른 방향으로 갈 것입니다.

TraceListener콘솔 용과 로그 파일 용으로 인스턴스화 하십시오. 그 후에 Trace.Write코드에서 Console.Write. 나중에 로그 또는 콘솔 출력을 제거하거나 다른 로깅 메커니즘을 연결하는 것이 더 쉬워집니다.

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.");
}

내가 기억할 수있는 한, 애플리케이션 구성에서 리스너를 정의하여 빌드를 건드리지 않고도 로깅을 활성화하거나 비활성화 할 수 있습니다.


4
완벽합니다-감사합니다. 나는 Log4Net을 알고 있었지만 이와 같은 것을 위해 라이브러리를 가져와야하는 것은 잘못된 것 같습니다.
xyz

3
나는 그들이 Trace를 더 많이 만들지 않는 이유를 모르겠습니다. 생산 규모의 로깅에는 잘 작동하는 것처럼 보이지만 모두가이를 수행하기 위해 추가 라이브러리 (예 : log4net)를 사용하기를 원합니다.
Coderer

이것은 단방향 미러링입니다. 대화 형 콘솔이 있고 사용자로부터 데이터를 얻고이 솔루션이 작동하지 않는 파일에 모든 것을 기록하려는 경우 의미합니다. 이 간단한 사실에도 불구하고 내 질문은 종결되었습니다. 여기 : stackoverflow.com/questions/3886895/…
Xaqron

6
저는이 솔루션이 정말 마음에 들었 기 때문에 약간의 정리와 몇 가지 걸림돌에 대한 설명이 포함 된 간단한 블로그를 만들었습니다. mcrook.com/2014/11/quick-and-easy-console-logging-trace.html 훌륭한 솔루션에 감사드립니다 :)
Michael Crook

51

이것은 입력을 파일과 콘솔 모두로 리디렉션 할 수 있도록 TextWriter를 하위 클래스로 만드는 간단한 클래스입니다.

이렇게 사용하세요

  using (var cc = new ConsoleCopy("mylogfile.txt"))
  {
    Console.WriteLine("testing 1-2-3");
    Console.WriteLine("testing 4-5-6");
    Console.ReadKey();
  }

수업은 다음과 같습니다.

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;
    }
  }

}

5
이것이 가장 완벽한 솔루션이라고 생각합니다. Write / WriteLine 메서드의 모든 오버로드를 재정의 할 필요가 없으며 다른 코드에 투명합니다. 따라서 모든 콘솔 활동은 다른 코드를 변경하지 않고 파일에 복제됩니다.
papadi

3
감사합니다! 그것은 굉장! 방금 File.CreateFile.Open (path, FileMode.Append, FileAccess.Write, FileShare.Read); 시작할 때 오래된 로그를 지우고 싶지 않고 프로그램이 실행되는 동안 로그 파일을 열 수 있기를 원하기 때문입니다.

1
이렇게하면에 대한 기존 호출을 모두 바꿀 필요가 없었 Console.WriteLine()습니다.
x6herbius

스윙하는 사람에게는 이것이 어떻게 수행되는지 혼란 스럽습니다. 를 찾으십시오 Console.SetOut(doubleWriter);. 콘솔의 전역을 수정하는 것은 거의 전역이 아닌 응용 프로그램에서 작업하는 데 너무 익숙하기 때문에 약간의 시간이 걸렸습니다. 좋은 물건!
Douglas Gaskell

13

log4net을 확인하십시오 . log4net을 사용하면 단일 로그 문으로 두 위치에 로그 메시지를 출력 할 수있는 콘솔 및 파일 어 펜더를 설정할 수 있습니다.


6
글쎄, 나는 이미 거기에있는 것으로 할 수 있다면 여분의 libs는 피해야한다고 생각합니다.
Oliver Friedrich

log4net도 추천하지만 NLog가 커뮤니티에서 자리를 차지하고있는 것 같습니다.
Mark Richman 2014

10

>명령을 사용하여 출력을 파일로 리디렉션 할 수 없습니까 ?

c:\>Console.exe > c:/temp/output.txt

미러링해야하는 경우 tee출력을 파일로 분할 하는 win32 버전을 찾을 수 있습니다 .

PowerShell에서 를 실행 하려면 /superuser/74127/tee-for-windows 를 참조 하십시오.


8
거울이 필요 해요. 그것이 주제와 본문에서 언급 된 이유입니다. 팁 주셔서 감사합니다 :)
xyz

8

TextWriter 클래스의 하위 클래스를 만든 다음 Console.SetOut 메서드를 사용하여 해당 인스턴스를 Console.Out에 할당 할 수 있습니다. 특히 로그 메서드의 두 메서드에 동일한 문자열을 전달하는 것과 동일한 작업을 수행합니다.

또 다른 방법은 자신의 콘솔 클래스를 선언하고 using 문을 사용하여 클래스를 구분할 수 있습니다.

using Console = My.Very.Own.Little.Console;

표준 콘솔에 액세스하려면 다음이 필요합니다.

global::Console.Whatever

8

편집 :이 방법은 타사 패키지에서 가져온 콘솔 정보를 리디렉션 할 수있는 가능성을 제공합니다. WriteLine 메서드를 재정의하는 것은 내 상황에 적합하지만 타사 패키지에 따라 다른 Write 메서드를 재정의해야 할 수도 있습니다.

먼저 CombinedWriter와 같이 StreamWriter에서 고유 한 새 클래스를 만들어야합니다.

그런 다음 Console.Out으로 CombinedWriter의 새 인스턴스를 초기화합니다.

마지막으로 Console.SetOut에 의해 콘솔 출력을 새 클래스의 인스턴스로 리디렉션 할 수 있습니다.

다음 코드는 새로운 수업이 저에게 효과적입니다.

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);
    }
}

이렇게하면 콘솔에 표시되는 내용을 놓치지 않습니다.
계속 생각

1
당신은 다음과 같은 방법을 오버라이드 (override) public override void Write(char value);, public override void Write(char[] buffer);, public override void Write(string value);public override void Write(char[] buffer, int index, int count);. 그렇지 않으면 WriteLine(format, ...)방법 을 사용하면 콘솔에 인쇄되지 않습니다 .
Dmytro Ovdiienko 2015

6

Log4net 이이를 수행 할 수 있습니다. 다음과 같이 작성합니다.

logger.info("Message");

구성에 따라 출력물이 콘솔, 파일 또는 둘 다로 이동할지 여부가 결정됩니다.


4

이미 사용하고있는 것이 최선의 접근 방식이라고 생각합니다. 본질적으로 출력을 미러링하는 간단한 방법입니다.

먼저 처음에 전역 TextWriter를 선언합니다.

private TextWriter txtMirror = new StreamWriter("mirror.txt");

그런 다음 작성 방법을 만드십시오.

// Write empty line
private void Log()
{
    Console.WriteLine();
    txtMirror.WriteLine();
}

// Write text
private void Log(string strText)
{
    Console.WriteLine(strText);
    txtMirror.WriteLine(strText);
}

이제, 대신에 사용하여 Console.WriteLine("...");, 사용 Log("...");. 그렇게 간단합니다. 더 짧습니다!


커서 위치 ( Console.SetCursorPosition(x, y);) 를 이동하면 문제가있을 수 있지만 그렇지 않으면 잘 작동합니다. 나도 사용합니다!

편집하다

물론 Console.Write();WriteLines 만 사용하지 않는 경우 동일한 방법으로 메서드를 만들 수 있습니다.


1
이것이 가장 간단한 해결책입니다. 프로그램 끝에 다음을 추가하는 것을 잊지 마십시오. <br/> txtMirror.Flush (); txtMirror.Close ();
Dominic Isaia

3

Arul이 제안한대로 using Console.SetOut을 사용하여 출력을 텍스트 파일로 리디렉션 할 수 있습니다.

Console.SetOut(new StreamWriter("Output.txt"));

2

사용자 Keep Thinking의 제안 인 StreamWriter에서 상속 된 클래스 사용 결정이 작동합니다. 하지만 생성자 base.AutoFlush = true에 추가해야했습니다.

{
    this.console = console;
    base.AutoFlush = true;
}

소멸자에 대한 명시 적 호출 :

public new void Dispose ()
{
    base.Dispose ();
}

그렇지 않으면 모든 데이터를 기록한 것보다 먼저 파일이 닫힙니다.

나는 그것을 다음과 같이 사용하고 있습니다.

CombinedWriter cw = new CombinedWriter ( "out.txt", true, Encoding.Unicode, 512, Console.Out );
Console.SetOut (cw);

2

우수한 솔루션을 위해 계속 생각해 주셔서 감사합니다! (내 목적을 위해) 콘솔 디스플레이에만 예상되는 특정 콘솔 쓰기 이벤트를 로깅하지 않도록 몇 가지 추가 재정의를 추가했습니다.

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();
        }
    }
}

Dispose 메서드를 교체 한 다음 base.Dispose ()를 호출하는 특별한 이유는 무엇입니까?
아담 Plocher

1

제어하지 않는 코드 (예 : 타사 라이브러리)에서 콘솔 출력을 복제하는 경우 TextWriter의 모든 구성원을 덮어 써야합니다. 코드는이 스레드의 아이디어를 사용합니다.

용법:

using (StreamWriter writer = new StreamWriter(filePath))
{
   using (new ConsoleMirroring(writer))
   {
       // code using console output
   }
}

ConsoleMirroring 클래스

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);
        }
    }
}

0

TextWriter에서 상속 된 자체 클래스를 구현하고 WriteLine 메서드를 재정 의하여 Console.Out to Trace의 투명한 미러링을 실제로 만들 수 있습니다.

WriteLine에서 파일에 쓰도록 구성 할 수있는 Trace에 쓸 수 있습니다.

이 답변이 매우 유용하다는 것을 알았습니다. https://stackoverflow.com/a/10918320/379132

그것은 실제로 나를 위해 일했습니다!


0

내 대답은 가장 많이 득표 한 비 승인 된 대답 과 지금까지 가장 우아한 해결책이라고 생각하는 가장 적은 투표를 기반으로합니다 . 사용할 수있는 스트림 유형 (예 :를 사용할 수 있음) 측면에서 좀 더 일반적 MemoryStream이지만 간결성을 위해 후자의 답변 에 포함 된 모든 확장 기능 을 생략했습니다.

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);
    }
}

용법:

using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName)))
using (var writer = new ConsoleMirrorWriter(stream))
{
    // Code using console output.
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.