



Взгляните на документы и исходный код для ConsoleHandler - я уверен, что вы могли бы легко написать версию, которая просто использует System.err вместо System.out. (Честно говоря, жаль, что ConsoleHandler не позволяет это настроить.)
Тогда это просто случай настройки системы ведения журнала для использования вашего нового StdoutHandler (или как вы его называете) обычным способом.
Да, но я подозреваю, что вы хотите создать подкласс StreamHandler, чтобы не пытаться закрыть System.err.
Если вы используете ведение журнала Java, вы можете изменить обработчик по умолчанию:
Например, для файлов: Обработчик fh = новый FileHandler (FILENAME); Logger.getLogger (LOGGER_NAME) .addHandler (fh);
Если вы хотите выводить в поток, вы можете использовать StreamHandler, я думаю, вы можете настроить его с любым потоком вывода, который вам нравится, включая системный поток.
Я придумал один способ. Сначала удалите обработчик консоли по умолчанию:
setUseParentHandlers (ложь);
Затем создайте подкласс ConsoleHandler и в конструкторе:
setOutputStream (System.out);
Лучше обернуть System.out самореализованным OutputStream, чтобы не закрывать его при следующем вызове setOutputStream(...) или LogManager.reset().
Кроме того, не вызывайте суперконструктор (ConsoleHandler), поскольку он устанавливает System.err, и вы закроете его при вызове setOutputStream(System.out). Или вы можете просто создать подкласс StreamHandler и вызвать в super( OutputStream, Formatter).
Если вы установите setUseParentHandlers (false); он установлен только для ТОГО класса. Другие классы в приложении по-прежнему будут передавать его в stderr.
Если сделать это для корневого класса ведения журнала (Logger.GLOBAL_LOGGER_NAME), ведение журнала консоли будет отключено для всех классов.
Просто расширите 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(){}
};
Но в наши дни ... есть ли способ сделать это без реализации специального обработчика ??
Я прибыл в
SimpleFormatter fmt = new SimpleFormatter();
StreamHandler sh = new StreamHandler(System.out, fmt);
logger.addHandler(sh);
Это не отключает обработчик по умолчанию. Просто следуйте ответу stackoverflow.com/a/2533250/873282
Хм, я просто несколько раз укусил за ногу, пытаясь совершить этот подвиг. Перед тем, как начать поиск в 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, были очень полезны.)
Идеальный. Надо сказать, что дизайнеры не совсем упростили задачу ... почему они не могут предвидеть эту потребность? Имейте в виду, что, похоже, то же самое и с другими фреймворками ведения журналов: ваша первая задача? Прыгайте через несколько сложных обручей!
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();
}
}
Я не могу просматривать журналы, пока приложение не будет закрыто. Вы хоть представляете, как просматривать логи в реальном времени?
Я думаю, что ConsoleHandler используется по умолчанию, есть StreamHandler, который может печатать в любой другой поток.