Java Language
로깅 (java.util.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()});
}
}
로깅 수준
자바 로깅 API는 7 단계로 구성되어 있습니다 . 내림차순의 레벨은 다음과 같습니다.
-
SEVERE
(최고 값) -
WARNING
-
INFO
-
CONFIG
-
FINE
-
FINER
-
FINEST
(최저치)
기본 수준은 INFO
(그러나 이는 시스템에 따라 다르며 가상 시스템을 사용함).
참고 : 또한 레벨 OFF
(로그 오프를 끄는 데 사용할 수 있음) 및 ALL
( OFF
의 오 퍼티)이 있습니다.
이 코드 예제 :
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이 스택 머신이라는 사실을 잊어 버렸습니다. 즉, 메서드 를 실행 하기 전에 모든 메서드의 매개 변수가 계산됩니다.
이 사실은 Java 로깅, 특히 FINE
, FINER
, FINEST
와 같은 저수준의 로깅 용으로 기본적으로 사용되지 않는 로깅에 중요합니다. takeOrder()
메소드의 자바 바이트 코드를 살펴 보겠습니다.
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 행은 실제 로깅을 실행합니다. 이전의 모든 작업 (로딩 변수, 새로운 객체 생성, format
메소드의 문자열 연결)은 로깅 수준을 FINE
보다 높게 (기본적으로는) 설정하면 아무 것도 할 수 없습니다. 이러한 로깅은 불필요한 메모리 및 프로세서 리소스를 소비하므로 매우 비효율적 일 수 있습니다.
그렇기 때문에 사용하려는 레벨이 활성화되어 있는지 묻는 것이 좋습니다.
올바른 방법은 다음과 같아야합니다.
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
}
자바 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
구조는 더 이상 필요하지 않습니다.