Javaでコンソール出力を監視する必要があります。ストリーミング時に出力を取得するいくつかの異なる方法を試しましたが、いくつかの落とし穴に陥りました(同じ出力をループし、出力の一部のみがキャプチャされ、出力が失われます)。別の方法で取り組むことにしました。
人気のゲームMinecraftのサーバー用のJavaプラグインを開発していますが、他のプラグインからのコンソール出力を監視できる必要があります。
これを行う良い方法は、コンソール出力をファイルにリダイレクトし、ファイルをチェックし、必要なことをすべて実行し、さらに入力するためにファイルをクリアする定期的な非同期タスクを設定することだと思います。System.setOut(PrintStream stream);を使用するだけでこれを実行できると思います。そして私がグーグルで見つけることができる多くのガイドの1つ。
しかし、問題があり、それが今日ここで私が尋ねている理由です。通常のようにコンソールにとどまるにはコンソール出力が必要なので、「ミラーリング」します。プラグインを編集して別の場所に出力することはできません。Javaプラグインが実行できるものからのものである必要があります。確かに、ファイルのスケジュールされたチェックごとに、すべてをコンソールに再印刷することはできますが、一度にブロックが印刷されることになり、理想的ではありません。これが可能であることを願っています。ありがとうございました!
編集:私は完全に説明したとは思いません。「プラグイン」のクラスは、私が開発しているプログラムによって実行されます。クラスの実行方法を変更したり、他のプラグインがコンソールに出力する方法を変更したりすることはできません。また、コンソール出力をログ記録用のファイルに転送したくありません。そのアイデアは、解析中に一時的な場所に保持することだけです。理想的には、コンソール出力の各行parseString(String line)
を、行の内容に応じて操作を実行する関数()に渡す必要があります。また、ストリームの内容を1行ずつ正しく読み取る方法がわからないので、何かアイデアがあれば教えてください。:)
3 に答える
変更する前に System.out をキャプチャし、TeeOutputStreamを使用します。
OutputStream myCaptureStream = ...;
PrintStream original = System.out;
OutptStream outputtee = new TeeOutputStream(originalOut, myCaptureStream);
PrintStream printTee = new PrintStream(outputTee);
System.setOut(printTee);
出力ストリーム (myCaptureStream) を入力ストリームに変換する
- Java 標準ライブラリ PipedOutputStreamを使用します
new PipedOutputStream
。注意深く読んでください - 別のスレッドでリーダーを実行する必要があります。 - 入力ストリームをReaderに変換し、
- そしてそれをBufferedReaderに。
BufferedReader はreadLine
メソッドを提供します。
擬似コード:
// Feed myCaptureStream to TeeOutputStream
OutputStream myCaptureStream = new PipedOutputStream();
// Prepare to capture data being written to that output stream
InputStream myCaptureAsInputStream = new PipedInputStream(myCaptureStream);
Reader myCaptureReader = new InputStreamReader(myCaptureAsInputStream);
BufferedReader myCaptureBuffered = new BufferedReader(myCaptureReader, 1024);
// This must run on separate reader thread; in spin loop:
myCaptureBuffer.readLine
System.out と System.err を変更して、独自のカスタム PrintStreams への参照にすることができます。このソリューションはクロス プラットフォームであり、.NET などのプラットフォーム固有のヘルパー実行可能ファイルを使用するのとは異なりますtee
。
System.setOut(PrintStream) のドキュメント
次のような独自の PrintStream サブクラスを作成できます。
class MirroringPrintStream extends PrintStream
{
PrintStream first, second;
public MirroringPrintStream(PrintStream first, PrintStream second)
{
// fail now rather than later
if (first == null || second == null) throw new NullPointerException();
this.first = first;
this.second = second;
}
@override
// methods go here (I do believe there are rather a lot of them, but they will all look the same)
}
その後、ログ ファイルに対して開いた PrintStream のSystem.setOut(new MirroringPrintStream(System.out, myLogStream))
場所を使用できます。myLogStream
他の何かが定期的に切り詰めるファイルへの追加をこれがどのように処理するかはわかりません。少し試してみてください。
他のすべてが失敗した場合は、irc.esper.net にアクセスして #risucraft で質問してください
これがコンソール出力の友好的な引き継ぎであると仮定すると、独自のストリームにログを記録し、それをコンソールにミラーリングしてみませんか?