Java Language
ロギング(java.util.logging)
サーチ…
デフォルトロガーの使用
次の例は、デフォルトのlogging apiを使用する方法を示しています。
import java.util.logging.Level;
import java.util.logging.Logger;
public class MyClass {
// retrieve the logger for the current class
private static final Logger LOG = Logger.getLogger(MyClass.class.getName());
public void foo() {
LOG.info("A log message");
LOG.log(Level.INFO, "Another log message");
LOG.fine("A fine message");
// logging an exception
try {
// code might throw an exception
} catch (SomeException ex) {
// log a warning printing "Something went wrong"
// together with the exception message and stacktrace
LOG.log(Level.WARNING, "Something went wrong", ex);
}
String s = "Hello World!";
// logging an object
LOG.log(Level.FINER, "String s: {0}", s);
// logging several objects
LOG.log(Level.FINEST, "String s: {0} has length {1}", new Object[]{s, s.length()});
}
}
ロギングレベル
JavaロギングApiには7 つのレベルがあります 。降順のレベルは次のとおりです。
-
SEVERE
(最高値) -
WARNING
-
INFO
-
CONFIG
-
FINE
-
FINER
-
FINEST
(最低値)
デフォルトのレベルはINFO
(ただし、これはシステムによって異なり、仮想マシンを使用します)。
注意 :レベルOFF
(ロギングをオフにするために使用できる)とALL
( OFF
のoposite)もあります。
このコード例:
import java.util.logging.Logger;
public class Levels {
private static final Logger logger = Logger.getLogger(Levels.class.getName());
public static void main(String[] args) {
logger.severe("Message logged by SEVERE");
logger.warning("Message logged by WARNING");
logger.info("Message logged by INFO");
logger.config("Message logged by CONFIG");
logger.fine("Message logged by FINE");
logger.finer("Message logged by FINER");
logger.finest("Message logged by FINEST");
// All of above methods are really just shortcut for
// public void log(Level level, String msg):
logger.log(Level.FINEST, "Message logged by FINEST");
}
}
デフォルトでは、このクラスを実行すると、レベルがCONFIG
より高いメッセージのみが出力されます。
Jul 23, 2016 9:16:11 PM LevelsExample main
SEVERE: Message logged by SEVERE
Jul 23, 2016 9:16:11 PM LevelsExample main
WARNING: Message logged by WARNING
Jul 23, 2016 9:16:11 PM LevelsExample main
INFO: Message logged by INFO
複雑なメッセージのロギング(効率的)
多くのプログラムで見られるログのサンプルを見てみましょう。
public class LoggingComplex {
private static final Logger logger =
Logger.getLogger(LoggingComplex.class.getName());
private int total = 50, orders = 20;
private String username = "Bob";
public void takeOrder() {
// (...) making some stuff
logger.fine(String.format("User %s ordered %d things (%d in total)",
username, orders, total));
// (...) some other stuff
}
// some other methods and calculations
}
上の例は完璧に見えますが、多くのプログラマーはJava VMがスタックマシンであることを忘れています。つまり、メソッドを実行する前に 、すべてのメソッドのパラメータが計算されます。
この事実は、特にFINE
、 FINER
、 FINEST
ようなデフォルトでは無効になっているような低レベルのログを記録するために、Javaのログインには不可欠です。 takeOrder()
メソッドのJavaバイトコードを見てみましょう。
javap -c LoggingComplex.class
の結果は次のようになります。
public void takeOrder();
Code:
0: getstatic #27 // Field logger:Ljava/util/logging/Logger;
3: ldc #45 // String User %s ordered %d things (%d in total)
5: iconst_3
6: anewarray #3 // class java/lang/Object
9: dup
10: iconst_0
11: aload_0
12: getfield #40 // Field username:Ljava/lang/String;
15: aastore
16: dup
17: iconst_1
18: aload_0
19: getfield #36 // Field orders:I
22: invokestatic #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
25: aastore
26: dup
27: iconst_2
28: aload_0
29: getfield #34 // Field total:I
32: invokestatic #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
35: aastore
36: invokestatic #53 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
39: invokevirtual #59 // Method java/util/logging/Logger.fine:(Ljava/lang/String;)V
42: return
39行目は実際のロギングを実行します。ロギングレベルがFINE
よりも高く(デフォルトでは)設定されていれば、以前のすべての作業(変数のロード、新しいオブジェクトの作成、文字列をformat
メソッドで連結)は何もできません。このようなロギングは、非常に非効率的であり、不必要なメモリとプロセッサリソースを消費します。
そのため、使用するレベルが有効になっているかどうかを確認する必要があります。
適切な方法は次のとおりです。
public void takeOrder() {
// making some stuff
if (logger.isLoggable(Level.FINE)) {
// no action taken when there's no need for it
logger.fine(String.format("User %s ordered %d things (%d in total)",
username, orders, total));
}
// some other stuff
}
Java 8以降:
Loggerクラスには、 Supplier<String>
asパラメータを取る追加のメソッドがあります。これは単にラムダによって提供されます。
public void takeOrder() {
// making some stuff
logger.fine(() -> String.format("User %s ordered %d things (%d in total)",
username, orders, total));
// some other stuff
}
Suppliers get()
メソッドget()
この場合はラムダ)は、対応するレベルが有効になったときにのみ呼び出され、 if
構造はもう必要ありません。