Использование java.util.logging API для регистрации разных уровней в отдельные файлы

#java #java.util.logging

#java #java.util.logging

Вопрос:

я хотел бы знать, как использовать java.util.logging API, чтобы сообщение журнала записывалось в разные файлы журнала в зависимости от используемого уровня. Если уровень — INFO, то я хотел бы, чтобы сообщение было записано в /log/info.log и так далее. 3 определенных уровня: серьезный, предупреждение и информация.

Комментарии:

1. какой Java logging API вы используете? Для log4j, java util logging и slf4j вы можете настроить приложения, которые делают то, что вы хотите, но конфигурация отличается для каждого из них.

2. Извините, я не использую Log4j, но я использую java logging api, предоставляемый jdk.

Ответ №1:

Вы используете пользовательский Handlers интерфейс для записи записей журнала.

Вот простой, но полный пример, на котором вы можете основываться.

 import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

public class LevelBasedFileHandler extends FileHandler
{
    public LevelBasedFileHandler(final Level level) throws IOException, SecurityException
    {
        super();
        super.setLevel(level);
    }

    public LevelBasedFileHandler(final String s, final Level level) throws IOException, SecurityException
    {
        super(s);
        super.setLevel(level);
    }

    public LevelBasedFileHandler(final String s, final boolean b, final Level level) throws IOException, SecurityException
    {
        super(s, b);
        super.setLevel(level);
    }

    public LevelBasedFileHandler(final String s, final int i, final int i1, final Level level) throws IOException, SecurityException
    {
        super(s, i, i1);
        super.setLevel(level);
    }

    public LevelBasedFileHandler(final String s, final int i, final int i1, final boolean b, final Level level) throws IOException, SecurityException
    {
        super(s, i, i1, b);
        super.setLevel(level);
    }

    @Override
    public void setLevel() { throw new UnsupportedOperationException("Can't change after construction!"); }

    // This is the important part that makes it work
    // it also breaks the contract in the JavaDoc for FileHandler.setLevel() 
    @Override
    public void publish(final LogRecord logRecord)
    {
        if (logRecord.getLevel().equals(super.getLevel())
        {
            super.publish(logRecord);
        }
    }
}
 

и вот как это использовать

 try
{
    // I use the Anonymous logger here, but any named logger will work as well
    final Logger l = Logger.getAnonymousLogger();
    l.addHandler(new LevelBasedFileHandler("/tmp/info.log", Level.INFO));
    l.addHandler(new LevelBasedFileHandler("/tmp/warn.log", Level.WARNING));
    l.addHandler(new LevelBasedFileHandler("/tmp/server.log", Level.SEVERE));

    l.info("This is an INFO message");
    l.warning("This is a WARNING message");
    l.severe("This is a SEVERE message");
}
catch (final IOException e)
{
    // ignore this for this example, you should never do this in real code
}
 

вы получите три файла в /tmp каждом из которых содержатся только сообщения для каждого конкретного уровня журнала.

Обратите внимание, мне нравится подход в стиле внедрения зависимостей, требующий Level в конструкторе, чтобы вы не могли «забыть» вызвать .setLevel() при использовании этого подкласса. Я также отключил .setLevel() , потому что его вызов и изменение нарушили бы семантику подкласса »

Просто для полноты вы можете использовать a java.util.logging.Filter для выполнения того же самого. Это не так инкапсулировано, но это альтернатива. Это больше кода и более подробный, поэтому больше не получается правильно.

 final FileHandler infoFileHandler = new FileHandler("/tmp/info.log");
infoFileHandler.setFilter(new Filter()
{
    public boolean isLoggable(final LogRecord logRecord)
    {
        return logRecord.getLevel().equals(Level.INFO);
    }
});
 

Лично мне по-прежнему больше нравится подход к подклассу, он менее подвержен ошибкам и более самодокументирован с точки зрения его цели и намерения.

Комментарии:

1. Вам не нужно LevelBasedFileHandler , поскольку у каждого дескриптора есть setLevel . Просто h=new FileHandler(...); h.setLevel(...)

2. @bestss setLevel() ограничивается только сообщениями более низкого уровня, но принимает сообщения более высокого уровня. Прочитайте javadoc на нем. «Установите уровень журнала, указав, какие уровни сообщений будут регистрироваться этим обработчиком. Уровни сообщений ниже этого значения будут отброшены «. Требуется только указанные уровни.

3. @JarrodRoberson, действительно, хотя это странно, поскольку уровни — это фактически просто числа (т. Е. Диапазон), но вам все равно не нужно расширять класс, в этом случае есть встроенный фильтр. Что касается документа (я также использовал переопределенный jul, в оригинале слишком много синхронизаций)

Ответ №2:

Поскольку все говорят о log4j… Вот более полезный ответ:

Добавьте разные дескрипторы (обработчики файлов для файлов) и установите уровни для обработчиков. Уровень для регистратора должен позволять наиболее подробный / расслабленный, чтобы перейти к обработчикам.

Я не использую файл свойств для настройки jul.Регистратор, но просто какой-то самодельный xml. Если вы не можете сделать это через файл свойств, просто используйте logger.getHandler() и установите соответствующие уровни.

Ответ №3:

Предполагая, что вы используете log4j для ведения своих журналов. Вам нужно будет написать пользовательское приложение и добавить его в каждый регистратор.

  • Простые инструкции

В пользовательском приложении у вас просто есть оператор if, который просматривает тип журнала и выполняет необходимые действия. В частности, существуют приложения к файлам, которые могут быть расширены, чтобы очень естественно удовлетворить эту потребность. http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/FileAppender.html

  • Более элегантный пример

Вместо того , чтобы писать свой собственный код , попробуйте просто настроить конфигурационный файл !

http://www.vaannila.com/log4j/log4j-file-appender-example-1.html

Это сделает именно то , что вам нужно .

Комментарии:

1. Хорошо, можно ли сделать то же самое с помощью API ведения журнала, предоставляемого jdk?

2. На самом деле, решение, представленное в примере, — это не то, чего я хотел бы достичь, особенно решение с конфигурационным файлом. В этом решении протоколирование сообщения в том или ином файле зависит от того, в каком пакете вы находитесь.