Как изменить вывод консоли ведения журнала java с std err на std out?

Я использую стандартный ConsoleHandler от java.util.logging, и по умолчанию вывод консоли направляется в поток ошибок (например, System.err).

Как изменить вывод консоли на поток вывода (например, System.out)?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
39
0
42 326
13

Ответы 13

Взгляните на документы и исходный код для ConsoleHandler - я уверен, что вы могли бы легко написать версию, которая просто использует System.err вместо System.out. (Честно говоря, жаль, что ConsoleHandler не позволяет это настроить.)

Тогда это просто случай настройки системы ведения журнала для использования вашего нового StdoutHandler (или как вы его называете) обычным способом.

Я думаю, что ConsoleHandler используется по умолчанию, есть StreamHandler, который может печатать в любой другой поток.

Uri 11.10.2008 19:30

Да, но я подозреваю, что вы хотите создать подкласс StreamHandler, чтобы не пытаться закрыть System.err.

Jon Skeet 11.10.2008 21:59

Если вы используете ведение журнала Java, вы можете изменить обработчик по умолчанию:

Например, для файлов: Обработчик fh = новый FileHandler (FILENAME); Logger.getLogger (LOGGER_NAME) .addHandler (fh);

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

Я придумал один способ. Сначала удалите обработчик консоли по умолчанию:

setUseParentHandlers (ложь);

Затем создайте подкласс ConsoleHandler и в конструкторе:

setOutputStream (System.out);

Лучше обернуть System.out самореализованным OutputStream, чтобы не закрывать его при следующем вызове setOutputStream(...) или LogManager.reset().

amotzg 27.09.2012 07:54

Кроме того, не вызывайте суперконструктор (ConsoleHandler), поскольку он устанавливает System.err, и вы закроете его при вызове setOutputStream(System.out). Или вы можете просто создать подкласс StreamHandler и вызвать в super( OutputStream, Formatter).

amotzg 27.09.2012 07:58

Если вы установите setUseParentHandlers (false); он установлен только для ТОГО класса. Другие классы в приложении по-прежнему будут передавать его в stderr.

Если сделать это для корневого класса ведения журнала (Logger.GLOBAL_LOGGER_NAME), ведение журнала консоли будет отключено для всех классов.

koppor 18.11.2012 00:44

Просто расширите StreamHandler & в вызове конструктора Super (System.out,). Это позволит избежать закрытия System.err - Спасибо

Handler consoleHandler = new Handler(){
         @Override
            public void publish(LogRecord record)
            {
                if (getFormatter() == null)
                {
                    setFormatter(new SimpleFormatter());
                }

                try {
                    String message = getFormatter().format(record);
                    if (record.getLevel().intValue() >= Level.WARNING.intValue())
                    {
                        System.err.write(message.getBytes());                       
                    }
                    else
                    {
                        System.out.write(message.getBytes());
                    }
                } catch (Exception exception) {
                    reportError(null, exception, ErrorManager.FORMAT_FAILURE);
                }

            }

            @Override
            public void close() throws SecurityException {}
            @Override
            public void flush(){}
        };

Но в наши дни ... есть ли способ сделать это без реализации специального обработчика ??

Victor 26.08.2013 00:19

Я прибыл в

 SimpleFormatter fmt = new SimpleFormatter();
 StreamHandler sh = new StreamHandler(System.out, fmt);
 logger.addHandler(sh);

Это не отключает обработчик по умолчанию. Просто следуйте ответу stackoverflow.com/a/2533250/873282

koppor 18.11.2012 00:36

Хм, я просто несколько раз укусил за ногу, пытаясь совершить этот подвиг. Перед тем, как начать поиск в Google, мне удалось придумать следующий прием. Уродливо, но, похоже, он выполняет свою работу.

public class StdoutConsoleHandler extends ConsoleHandler {
  protected void setOutputStream(OutputStream out) throws SecurityException {
    super.setOutputStream(System.out); // kitten killed here :-(
  }
}

Остерегайтесь: вызов setOutputStream () из конструктора заманчиво, но он (как уже указал Джон Скит) закрывает System.err. Безумные навыки!

Если кто-то еще ищет решение этой проблемы. Вот что я наконец придумал: я просто создал подкласс StreamHandler и добавил дополнительный параметр MaxLevel, который проверяется в начале publish (). Если уровень события ведения журнала больше, чем MaxLevel, публикация больше не будет выполняться. Вот подробности:

MaxlevelStreamHandler.java Основной класс ниже.

package helper;

/**
 * The only difference to the standard StreamHandler is 
 * that a MAXLEVEL can be defined (which then is not published)
 * 
 * @author Kai Goergen
 */

import java.io.PrintStream;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.StreamHandler;

public class MaxlevelStreamHandler extends StreamHandler {

    private Level maxlevel = Level.SEVERE;  // by default, put out everything

    /**
     * The only method we really change to check whether the message
     * is smaller than maxlevel.
     * We also flush here to make sure that the message is shown immediately.
     */
    @Override
    public synchronized void publish(LogRecord record) {
        if (record.getLevel().intValue() > this.maxlevel.intValue()) {
            // do nothing if the level is above maxlevel
        } else {
            // if we arrived here, do what we always do
            super.publish(record);
            super.flush();
        }
    }

    /**
     * getter for maxlevel
     * @return
     */
    public Level getMaxlevel() {
        return maxlevel;
    }

    /**
     * Setter for maxlevel. 
     * If a logging event is larger than this level, it won't be displayed
     * @param maxlevel
     */
    public void setMaxlevel(Level maxlevel) {
        this.maxlevel = maxlevel;
    }

    /** Constructor forwarding */
    public MaxlevelStreamHandler(PrintStream out, Formatter formatter) {
        super(out, formatter);
    }

    /** Constructor forwarding */
    public MaxlevelStreamHandler() {
        super();
    }
}

Основной класс

Чтобы теперь отображать некоторые события в stdout, а некоторые - в stderr, просто настройте два StreamLogger, один для критических событий и один для всех остальных, и отключите стандартный логгер консоли:

// setup all logs that are smaller than WARNINGS to stdout
MaxlevelStreamHandler outSh = new MaxlevelStreamHandler(System.out, formatter);
outSh.setLevel(Level.ALL);
outSh.setMaxlevel(Level.INFO);
logger.addHandler(outSh);

// setup all warnings to stdout & warnings and higher to stderr
StreamHandler errSh = new StreamHandler(System.err, formatter);
errSh.setLevel(Level.WARNING);
logger.addHandler(errSh);

// remove default console logger
logger.setUseParentHandlers(false);

logger.info("info");
logger.warning("warning");
logger.severe("severe");

Надеюсь это поможет!

Обновление: я добавил super.flush () сразу после super.publish (), чтобы убедиться, что сообщение отображается сразу. Раньше у меня были проблемы с тем, что лог-сообщения всегда показывались в конце. Теперь это часть кода выше.

У меня была аналогичная проблема. Я хотел регистрировать ИНФОРМАЦИЮ и ниже в System.out и ПРЕДУПРЕЖДЕНИЕ и выше в System.err. Вот решение, которое я реализовал:

public class DualConsoleHandler extends StreamHandler {

    private final ConsoleHandler stderrHandler = new ConsoleHandler();

    public DualConsoleHandler() {
        super(System.out, new SimpleFormatter());
    }

    @Override
    public void publish(LogRecord record) {
        if (record.getLevel().intValue() <= Level.INFO.intValue()) {
            super.publish(record);
            super.flush();
        } else {
            stderrHandler.publish(record);
            stderrHandler.flush();
        }
    }
}

Конечно, вы могли бы сделать его более гибким, например, исключив жестко запрограммированную ссылку на Level.INFO. Но это сработало для меня, чтобы получить базовое двухпотоковое ведение журнала. (Кстати, советы о том, чтобы не создавать подклассы ConsoleHandler, чтобы не закрывать System.err, были очень полезны.)

Идеальный. Надо сказать, что дизайнеры не совсем упростили задачу ... почему они не могут предвидеть эту потребность? Имейте в виду, что, похоже, то же самое и с другими фреймворками ведения журналов: ваша первая задача? Прыгайте через несколько сложных обручей!

mike rodent 16.04.2016 18:26

ConsoleHandler сделает снимок System.err во время строительства. Один из вариантов - заменить глобальный поток ошибок глобальным исходящим потоком, а затем создать ConsoleHandler.

ConsoleHandler h = null;
final PrintStream err = System.err;
System.setErr(System.out);
try {
    h = new ConsoleHandler(); //Snapshot of System.err
} finally {
    System.setErr(err);
}

Это предполагает, что у кода есть разрешение на изменение потока ошибок и что никакой другой запущенный код не обращается к потоку ошибок. Короче говоря, это вариант, но есть более безопасные альтернативы.

Когда мы создаем новый объект ConsoleHandler, выходной поток по умолчанию - «system.err». К сожалению, Java не предоставляет никаких общедоступных методов для класса ConsoleHandler для установки выходного потока. Так что установить его можно только во время создания объекта. Поскольку класс ConsoleHandler расширяет StreamHandler, который имеет защищенный метод "setOutputStream" для явной установки потока вывода. Чтобы установить выходной поток для ConsoleHandler, просто переопределите этот метод во время нового вызова для создания объекта.

ConsoleHandler consoleHandler = new ConsoleHandler (){
            @Override
            protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
                super.setOutputStream(System.out);
            }
        };

Шаг 1: Установить родительские обработчики на false.

log.setUseParentHandlers(false);

Шаг 2: Добавить обработчик, который записывает в System.out

log.addHandler(new StreamHandler(System.out, new SimpleFormatter()));

Вот и все..

import java.io.IOException;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;

public class App {

     static final Logger log = Logger.getLogger("com.sample.app.App");

     static void processData() {
          log.info("Started Processing Data");
          log.info("Finished processing data");
     }

     public static void main(String args[]) throws IOException {
          log.setUseParentHandlers(false);

          log.addHandler(new StreamHandler(System.out, new SimpleFormatter()));

          processData();
     }
}

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

akvyalkov 03.11.2020 17:00

Другие вопросы по теме