私はJava.util.logging
の標準のConsoleHandler
を使用しています。デフォルトでは、コンソール出力はエラーストリーム(つまりSystem.err
)に送られます。
コンソール出力を出力ストリーム(つまり、System.out
)に変更するにはどうすればよいですか?
着きました
SimpleFormatter fmt = new SimpleFormatter();
StreamHandler sh = new StreamHandler(System.out, fmt);
logger.addHandler(sh);
うーん、私はこの偉業を成し遂げるために数回足に噛みついたところです。ここに行く前に、次のハックを思いついた。醜い、しかしそれは仕事を成し遂げたようです。
public class StdoutConsoleHandler extends ConsoleHandler {
protected void setOutputStream(OutputStream out) throws SecurityException {
super.setOutputStream(System.out); // kitten killed here :-(
}
}
注意:コンストラクタからsetOutputStream()を呼び出すのは魅力的ですが、(Jon Skeetが既に指摘したように)System.errを閉じます。マッドスキル!
私は一つの方法を考え出した。まず、デフォルトのコンソールハンドラーを削除します。
setUseParentHandlers(false);
次に、ConsoleHandlerをサブクラス化し、コンストラクターで次のようにします。
setOutputStream(System.out);
Handler consoleHandler = new Handler(){
@Override
public void publish(LogRecord record)
{
if (getFormatter() == null)
{
setFormatter(new SimpleFormatter());
}
try {
String message = getFormatter().format(record);
if (record.getLevel().intValue() >= Level.WARNING.intValue())
{
System.err.write(message.getBytes());
}
else
{
System.out.write(message.getBytes());
}
} catch (Exception exception) {
reportError(null, exception, ErrorManager.FORMAT_FAILURE);
}
}
@Override
public void close() throws SecurityException {}
@Override
public void flush(){}
};
同様の問題がありました。 INFO以下をSystem.out
に、WARNING以上をSystem.err
に記録したいと思っていました。これが私が実装したソリューションです:
public class DualConsoleHandler extends StreamHandler {
private final ConsoleHandler stderrHandler = new ConsoleHandler();
public DualConsoleHandler() {
super(System.out, new SimpleFormatter());
}
@Override
public void publish(LogRecord record) {
if (record.getLevel().intValue() <= Level.INFO.intValue()) {
super.publish(record);
super.flush();
} else {
stderrHandler.publish(record);
stderrHandler.flush();
}
}
}
もちろん、たとえばLevel.INFO
へのハードコードされた参照を除外することで、より柔軟にすることができます。しかし、これはいくつかの基本的なデュアルストリームログを取得するために私にとってはうまくいきました。 (ところで、System.err
を閉じないようにConsoleHandlerをサブクラス化しないことに関するヒントは非常に役に立ちました。)
ConsoleHandler のドキュメントとソースをご覧ください。System.outの代わりにSystem.errを使用するバージョンを簡単に記述できると思います。 (正直に言うと、ConsoleHandlerがこれを構成することを許可しないのは残念です。)
次に、通常の方法で新しいStdoutHandler(またはそれを呼び出すもの)を使用するようにロギングシステムを構成する場合にすぎません。
この問題の解決策を探している人がまだいる場合。これが最後に思いついたものです。StreamHandlerをサブクラス化し、追加のパラメーターMaxLevelを追加しました。これは、publish()の最初でチェックされます。ロギングイベントのレベルがMaxLevelより大きい場合、パブリッシュはそれ以上実行されません。詳細は次のとおりです。
MaxlevelStreamHandler.Java以下のメインクラス。
package helper;
/**
* The only difference to the standard StreamHandler is
* that a MAXLEVEL can be defined (which then is not published)
*
* @author Kai Goergen
*/
import Java.io.PrintStream;
import Java.util.logging.Formatter;
import Java.util.logging.Level;
import Java.util.logging.LogRecord;
import Java.util.logging.StreamHandler;
public class MaxlevelStreamHandler extends StreamHandler {
private Level maxlevel = Level.SEVERE; // by default, put out everything
/**
* The only method we really change to check whether the message
* is smaller than maxlevel.
* We also flush here to make sure that the message is shown immediately.
*/
@Override
public synchronized void publish(LogRecord record) {
if (record.getLevel().intValue() > this.maxlevel.intValue()) {
// do nothing if the level is above maxlevel
} else {
// if we arrived here, do what we always do
super.publish(record);
super.flush();
}
}
/**
* getter for maxlevel
* @return
*/
public Level getMaxlevel() {
return maxlevel;
}
/**
* Setter for maxlevel.
* If a logging event is larger than this level, it won't be displayed
* @param maxlevel
*/
public void setMaxlevel(Level maxlevel) {
this.maxlevel = maxlevel;
}
/** Constructor forwarding */
public MaxlevelStreamHandler(PrintStream out, Formatter formatter) {
super(out, formatter);
}
/** Constructor forwarding */
public MaxlevelStreamHandler() {
super();
}
}
メインクラス
Stdoutとstderrにいくつかのイベントを表示するには、2つのStreamLoggerをセットアップします。1つは重要なイベント用、もう1つはその他すべてのイベント用で、標準のコンソールロガーを無効にします。
// setup all logs that are smaller than WARNINGS to stdout
MaxlevelStreamHandler outSh = new MaxlevelStreamHandler(System.out, formatter);
outSh.setLevel(Level.ALL);
outSh.setMaxlevel(Level.INFO);
logger.addHandler(outSh);
// setup all warnings to stdout & warnings and higher to stderr
StreamHandler errSh = new StreamHandler(System.err, formatter);
errSh.setLevel(Level.WARNING);
logger.addHandler(errSh);
// remove default console logger
logger.setUseParentHandlers(false);
logger.info("info");
logger.warning("warning");
logger.severe("severe");
お役に立てれば!
更新:メッセージがすぐに表示されるように、super.publish()の直後にsuper.flush()を追加しました。以前は、ログメッセージが常に最後に表示されるという問題がありました。これは上記のコードの一部です。
新しいConsoleHandlerオブジェクトを作成する場合、デフォルトの出力ストリームは「system.err」です。悲しいことにJavaは、出力ストリームを設定するためのConsoleHandlerクラスのパブリックメソッドを提供していません。そのため、オブジェクトの作成時にのみ設定できます。ConsoleHandlerクラスは、保護されたメソッドを持つStreamHandlerを拡張します。出力ストリームを明示的に設定する "setOutputStream" ConsoleHandlerの出力ストリームを設定するには、オブジェクト作成の新しい呼び出し時にこのメソッドをオーバーライドするだけです。
ConsoleHandler consoleHandler = new ConsoleHandler (){
@Override
protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
super.setOutputStream(System.out);
}
};
ConsoleHandlerは、構築中にSystem.err
のスナップショットを取得します。 1つのオプションは、グローバルエラーストリームをグローバルアウトストリームと交換してから、ConsoleHandlerを作成することです。
ConsoleHandler h = null;
final PrintStream err = System.err;
System.setErr(System.out);
try {
h = new ConsoleHandler(); //Snapshot of System.err
} finally {
System.setErr(err);
}
これは、コードにエラーストリームを変更する権限があり、他の実行中のコードがエラーストリームにアクセスしていないことを前提としています。要するに、これはオプションですが、より安全な代替策があります。
Javaロギングを使用する場合、デフォルトのハンドラーを変更できます:
たとえば、ファイルの場合:Handler fh = new FileHandler(FILENAME); Logger.getLogger(LOGGER_NAME).addHandler(fh);
StreamHandlerを使用してストリームに出力したい場合は、システムストリームを含め、好きな出力ストリームで構成できます。
SetUseParentHandlers(false);を設定すると、 THATクラスのみが設定します。アプリ内の他のクラスは、それをstderrに渡します。