Если я правильно понимаю, вы в конечном итоге получите свойства ведения журнала, которые выглядят так:
java.util.logging.ConsoleHandler.level = FINER
org.apache.catalina.realm.level = FINER
В разделе Обзор ведения журнала Java 1.1 указано:
Приложения осуществляют регистрацию вызовов на объектах Logger. Регистраторы организованы в иерархическое пространство имен, и дочерние регистраторы могут наследовать некоторые свойства журналирования от своих родителей в пространстве имен.
При чтении имен регистратора родительские регистраторы находятся слева от точек.
Следовательно, org.apache.catalina
является родителем org.apache.catalina.realm
и org.apache.catalina.realm
и org.apache.catalina.core
.
Код исполняющего кода должен требовать регистратор , чтобы он существовал. Простое добавление строк в файл свойств не создает логгеры. Если бы это было так, они бы просто собрали мусор в любом случае. Это означает, что у вас есть дерево логгеров A <- B <- C
. Вы хотите установить уровень для B
и, следовательно, для всех B
дочерних элементов, чтобы добавить строку A.B.level
в файл свойств. Однако во время выполнения требуются следующие регистраторы: A
и C
.
Так что вам нужно работать с "" <- A <- A.B.C
, когда вы ожидаете "" <- A <- A.B <- A.B.C
Собирая все это вместе, я думаю, что во время выполнения ваши логгеры будут выглядеть так:
"" <- org.apache.catalina <- org.apache.catalina.realm.RealmBase
, и никакой код Tomcat не создал фактического регистратора с именем org.apache.catalina.realm
.
Вы можете проверить, подключив JConsole к запуску JVM и проверке вкладки MBean и перечислению имен регистратора. В Tomcat это не сработает, поскольку возвращаемые средства ведения журнала зависят от вызывающего загрузчика классов.
Чтобы обойти это, вы можете использовать опцию config для запроса и удержания регистратора в памяти. Вам просто нужно установить это в пользовательском коде по системному классу path .
В противном случае вы должны указать все известные имена дочерних регистраторов в файле свойств, которые могут быть подробными.
Первая идея: если мы посмотрим на специфику CSS, мы знаем, что .mydiv {color: red} не так специфичен, как div.mydiv {color: green}, поэтому div.mydiv содержит текст красного цвета? Под наследованием понимается, если не указано, что такое анти-наследование.
В отличие от CSS, JUL имеет дерево логгера времени выполнения и файл свойств. Это дерево логгера времени выполнения динамически корректируется, поскольку выполнение кода требует регистраторов. Свойства используются всегда, только если код требует регистратора. Указание имени регистратора в файле свойств ничего не значит, если регистратор не создан кодом. Это может изменить родителей регистратора и, следовательно, уровень. Дайте ему вращение:
package so;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class TheMissingParent {
private static final Logger[] LAZY_ONE;
static {
LAZY_ONE = new Logger[] { Logger.getLogger("org.apache.catalina"),
Logger.getLogger("org.apache.catalina.realm.RealmBase") };
}
private static volatile Logger[] LAZY_TWO;
public static void main(String[] args) {
loadProperties();
printAncestors(LAZY_ONE);
findlLongLostParents();
System.out.println("====");
printAncestors(LAZY_ONE);
}
private static void loadProperties() {
Properties props = new Properties();
props.put("org.apache.catalina.realm.level", "FINER");
try(ByteArrayOutputStream out = new ByteArrayOutputStream()) {
props.store(out, "");
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
private static void findlLongLostParents() {
LAZY_TWO = new Logger[] {Logger.getLogger("org.apache.catalina.realm") };
}
private static void printAncestors(Logger[] loggers) {
// System.out.println(loggers.toString());
for (Logger l : loggers) {
printAncestors(l);
System.out.println();
}
}
private static void printAncestors(Logger l) {
if (l != null) {
printAncestors(l.getParent());
System.out.print("<-");
String name = l.getName();
if (name != null && name.isEmpty()) {
System.out.append("\"\"");
} else {
System.out.append(name);
}
for(Logger p = l; p != null; p = p.getParent()) {
Level lvl = p.getLevel();
if (lvl != null) {
System.out.append('{').append(lvl.getName()).append('}');
break;
}
}
}
}
}
Будет выведено:
<-""{INFO}<-org.apache.catalina{INFO}
<-""{INFO}<-org.apache.catalina{INFO}<-org.apache.catalina.realm.RealmBase{INFO}
====
<-""{INFO}<-org.apache.catalina{INFO}
<-""{INFO}<-org.apache.catalina{INFO}<-org.apache.catalina.realm{FINER}<-org.apache.catalina.realm.RealmBase{FINER}
Это основная проблема. Если Tomcat (или некоторый пользовательский код) никогда не требует регистратора org.apache.catalina.realm
, то строка в файле свойств - просто мертвый код.
Во-вторых, если вы так говорите, ни для org.apache.catalina, ни для org.apache, ни для org, ни для `` не должно быть уровня INFO, если вы так говорите, так откуда же берется значение INFO?
Это поведение описано в документах уровня класса LoggerManager :
Если ни одно из этих свойств не определено, то, как описано выше, LogManager будет считывать свою первоначальную конфигурацию из файла свойств "lib / logging.properties" в каталоге JRE.
Корневой регистратор с именем пустой строки ""
является родителем всех регистраторов. Корневой регистратор всегда создается.