Как изменить вывод консоли ведения журнала Java с std err на std out? - PullRequest
29 голосов
/ 11 октября 2008

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

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

Ответы [ 12 ]

13 голосов
/ 19 января 2011

Я прибыл в

 SimpleFormatter fmt = new SimpleFormatter();
 StreamHandler sh = new StreamHandler(System.out, fmt);
 logger.addHandler(sh);
9 голосов
/ 18 марта 2011

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

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

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

9 голосов
/ 25 мая 2010
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(){}
        };
8 голосов
/ 12 октября 2008

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

setUseParentHandlers (ложь);

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

setOutputStream (System.out);

4 голосов
/ 18 мая 2014

У меня была похожая проблема. Я хотел войти ИНФО и ниже в 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, были очень полезны.)

3 голосов
/ 11 октября 2008

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

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

2 голосов
/ 18 апреля 2012

Если кто-то еще ищет решение этой проблемы. Вот что я наконец-то придумал: я просто создал подкласс 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 (), чтобы убедиться, что сообщение отображается немедленно. Раньше у меня были проблемы с тем, что сообщения журнала всегда показывались в конце. Теперь это часть кода выше.

1 голос
/ 25 февраля 2017

Когда мы создаем новый объект 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 голос
/ 10 марта 2016

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);
}

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

1 голос
/ 11 октября 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...