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()});
}
}
Уровни регистрации
Java Logging Api имеет 7 уровней . Уровни в порядке убывания:
-
SEVERE
(наибольшее значение) -
WARNING
-
INFO
-
CONFIG
-
FINE
-
FINER
-
FINEST
(самое низкое значение)
Уровень по умолчанию - INFO
(но это зависит от системы и используется виртуальной машиной).
Примечание . Существуют также уровни OFF
(можно использовать для отключения регистрации) и ALL
(oposite 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
которые по умолчанию отключены. Давайте рассмотрим байт-код Java для 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
}
Поскольку Java 8:
Класс Logger имеет дополнительные методы, которые используют параметр Supplier<String>
, который может быть просто предоставлен лямбдой:
public void takeOrder() {
// making some stuff
logger.fine(() -> String.format("User %s ordered %d things (%d in total)",
username, orders, total));
// some other stuff
}
Метод get()
поставщиков get()
в этом случае лямбда - вызывается только тогда, когда соответствующий уровень включен, и поэтому конструкция if
больше не нужна.