コンソール出力のファイルへのミラーリング


88

C#コンソールアプリケーションで、コンソール出力をテキストファイルにミラーリングするスマートな方法はありますか?

現在、同じ文字列を両方Console.WriteLineInstanceOfStreamWriter.WriteLinelogメソッドに渡しています。

回答:


117

これはもう少し手間がかかるかもしれませんが、私は逆に行きます。

TraceListenerコンソール用に1つ、ログファイル用に1つをインスタンス化します。その後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など)に取り組みたいと考えています。
コーダー2009年

これは一方向のミラーリングです。つまり、インタラクティブコンソールがあり、ユーザーからデータを取得し、すべてをファイルに記録したい場合、このソリューションは機能しません。この単純な事実にもかかわらず、私の質問は閉じられています。ここで: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 2014年

3
ありがとう!それは素晴らしいです!File.CreateFile.Open(path、FileMode.Append、FileAccess.Write、FileShare.Read);に置き換えまし起動時に古いログを消去したくないので、プログラムの実行中にログファイルを開くことができるようにしたいからです。
ジョン

1
これにより、既存のすべての呼び出しを置き換える必要はありませんでしたConsole.WriteLine()。これはまさに私が望んでいたことでした。
x6herbius 2018

それによって揺れ動く人にとって、これがこれをどのように行うか混乱しています。を探しConsole.SetOut(doubleWriter);ます。これはコンソールのグローバルを変更しています。私は実際にはグローバルなものが何もないアプリケーションでの作業に慣れているので、少し時間がかかりました。良いもの!
ダグラスガスケル

13

log4netをチェックしてください。log4netを使用すると、1つのログステートメントで両方の場所にログメッセージを出力できるコンソールおよびファイルアペンダーを設定できます。


6
まあ、すでにそこにあるものでそれができるのであれば、余分なライブラリは避けるべきだと思います。
オリバーフリードリッヒ

log4netもお勧めしますが、NLogがコミュニティでその役割を果たしているようです。
マークリッチマン2014

10

>コマンドを使用して、出力をファイルにリダイレクトすることはできませんか?

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

ミラーリングする必要がある場合はtee、出力をファイルに分割するwin32バージョンを見つけてみてください。

PowerShellからteeを実行するには、https://superuser.com/questions/74127/tee-for-windowsを参照してください


8
ミラーリングする必要があります。それが主題と体で言及されている理由です。ヒントをありがとう:)
xyz

8

TextWriterクラスをサブクラス化してから、Console.SetOutメソッドを使用してそのインスタンスをConsole.Outに割り当てることができます。これは、特にlogメソッドの両方のメソッドに同じ文字列を渡すのと同じことを行います。

別の方法として、独自のコンソールクラスを宣言し、usingステートメントを使用してクラスを区別する場合があります。

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

標準のコンソールにアクセスするには、次のものが必要です。

global::Console.Whatever

8

編集:このメソッドは、サードパーティのパッケージから取得したコンソール情報をリダイレクトする可能性を提供します。WriteLineメソッドをオーバーライドすることは私の状況には適していますが、サードパーティのパッケージによっては他のWriteメソッドをオーバーライドする必要がある場合があります。

まず、StreamWriterに固有の新しいクラス(CombinedWriterなど)を作成する必要があります。

次に、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
あなたは、次のメソッドをオーバーライドする必要があり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();
DominicIsaia19年

3

Arulが提案しているように、usingConsole.SetOutを使用して出力をテキストファイルにリダイレクトできます。

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

2

StreamWriterから継承されたクラスを使用するという決定、ユーザーのKeep Thinkingによる提案は、機能します。しかし、コンストラクタベースに追加する必要がありました。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()を呼び出す特別な理由はありますか?
Adam Plocher 2014

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 toTraceの透過的なミラーリングを実際に作成できます。

WriteLineでは、それをTraceに書き込むことができ、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.