Java で stdout に書き込むライブラリがあります。log4j を使用して、この出力をログに記録したいと思います。(私はこのライブラリを作成していないため、ライブラリ内のコードを制御することはできません)。
これを行う簡単な方法はありますか?System.setOut は正しいアプローチですか? System.setOut には何を渡すのですか?
また、.NET/C# でこれを行うにはどうすればよいでしょうか?
1 つの解決策は、サブクラス化することOutputStream
です。実装するだけwrite( int b )
です。次に、コンストラクタPrintStream
で yourOutputStream
を作成します。
次のようになります。
public class L4JOS extends OutputStream {
logger = Logger.getLogger( "std.out" );
private int lineEnd = (int)'\n';
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
public void write( int b ) throws IOException {
baos.write( b );
if ( b == lineEnd ) {
logger.info( baos.toString() );
baos.reset();
}
}
}
マルチスレッドの場合は、より多くの作業があります。そして、アペンダーが System.out に行かないようにしてください。
取得したものをlog4jに記録し、System.setOutをそのOutputStreamのインスタンスにユーザーとして記録する独自のOutputStreamを実装できます。
これにより、log4j が標準出力にも出力する場合に無限ループが発生する可能性があることに注意してください。
したがって、何を log4j に渡し、何を元の stdout ストリームに渡すかを決定するために、おそらく何らかのフィルタリングを行う必要があります。
setOut() はグローバル変数であるため、使用したくありません。このライブラリのためだけに stdout をインターセプトしたいが、stdout を使用する必要がある可能性のある他のものを踏みにじる必要はありません。
可能であれば、ライブラリ関数を呼び出すコードを別のプロセス空間で実行してください。次に、そのプロセスから stdout を読み取り、ロガーに送信するスレッドを作成できます。
new Thread() {
public void run() {
ProcessBuilder pb = new ProcessBuilder(command);
Process p = pb.start();
BufferedReader in = new BufferedReader(p.getInputStream());
String line;
while ((line = in.readLine()) != null) {
log.info(line);
// or you could parse line and try to dynamically pick a log level
}
}
}
呼び出されたプロセスから呼び出し元に出力を返す良い方法が必要ですが、値を返すのと同じくらい簡単な場合は、標準出力の最後の行、または次の行として簡単に返すことができます。特別な信号コードか何か。
なぜあなたはそれをしたいのですか?sysout に直接書き込むべきではありません。sysout に出力する場合は、log4j に書き込み、コンソール アペンダーを構成する必要があります。
GUI アプリチェーンソーを標準出力に接続して、必要な結果を得ることができるはずです。