J'utilise la norme ConsoleHandler
de Java.util.logging
et par défaut, la sortie de la console est dirigée vers le flux d'erreur (I.E. System.err
).
Comment modifier la sortie de la console dans le flux de sortie (c'est-à-dire System.out
)?
Je suis arrivé à
SimpleFormatter fmt = new SimpleFormatter();
StreamHandler sh = new StreamHandler(System.out, fmt);
logger.addHandler(sh);
Hmm je viens de prendre un peu dans le pied plusieurs fois, essayant d'accomplir cet exploit. Avant de googler mon chemin ici, j'ai réussi à évoquer le piratage suivant. Moche, mais il semble faire le travail.
public class StdoutConsoleHandler extends ConsoleHandler {
protected void setOutputStream(OutputStream out) throws SecurityException {
super.setOutputStream(System.out); // kitten killed here :-(
}
}
SURVEILLER: Calling SetOutPutStream () à partir du constructeur est tentant, mais elle (comme Skeet Jon a déjà signalé) Fermer System.err. MAIN!
J'ai compris une façon. Tout d'abord, supprimez le gestionnaire de la console par défaut:
setruenthandlers (faux);
Puis Sous-classe Consolehandler et dans le constructeur:
systeutPutStream (System.out);
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(){}
};
J'avais un problème similaire. Je voulais connecter des informations et ci-dessous pour System.out
, et avertissement et ci-dessus à System.err
. Voici la solution que j'ai implémentée:
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();
}
}
}
Bien sûr, vous pouvez le rendre plus flexible en pratiquant la référence à codée dur à Level.INFO
, par exemple. Mais cela a bien fonctionné pour moi d'obtenir une exploitation forestière de base à double courant. (BTW, les astuces sur NON SUBCLASSING ConsoleHandler pour éviter de fermer le System.err
étaient très utiles.)
Regardez les documents et la source pour ConsoleHandler - Je suis sûr que vous pourriez facilement écrire une version qui utilise simplement System.err au lieu de System.out. (C'est dommage que ConsoleHandler n'autorise pas cela à être configuré, d'être honnête.)
Ensuite, il s'agit simplement d'un cas de configuration du système de journalisation pour utiliser votre nouveau STDOUTHANDLER (ou tout ce que vous l'appelez) normalement.
S'il y a toujours quelqu'un à la recherche d'une solution à ce problème. Voici ce que j'ai proposé finalement: je viens de sous-classé Streamhandler et ajouté un paramètre supplémentaire Maxlevel, qui est vérifié au début de la publication (). Si le niveau de l'événement de journalisation est supérieur à la maxlevel, la publication ne sera plus exécutée. Voici les détails:
maxlevelstreamhandler.java classe principale ci-dessous.
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();
}
}
classe principale
Pour afficher maintenant des événements dans STDOUT et certains à StDeRR, définissez simplement deux streamloggers, un pour les événements critiques et un pour tous les autres, et désactivez l'enregistreur de console standard:
// 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");
J'espère que cela t'aides!
Mise à jour: j'ai ajouté Super.flush () juste après Super.Publish () pour vous assurer que le message est montré immédiatement. Auparavant, j'ai eu des problèmes que les messages de journal ont toujours été montrés à la fin. Il fait maintenant partie du code ci-dessus.
Lorsque nous créons un nouvel objet Consolehandler, le flux de sortie par défaut est "System.err". Tristement Java ne fournit aucune méthode publique de la classe ConsoleHandler pour définir le flux de sortie. Donc, il ne peut donc être défini qu'au moment de la création d'objets. Comme ConsoleHandler Class prolonge Streamhandler, qui a une méthode protégée. "SetOutputTretstream" pour définir le flux de sortie explicitement. Pour définir le flux de sortie pour ConsoleHandler, il suffit de remplacer cette méthode au moment du nouvel appel de la création d'objets.
ConsoleHandler consoleHandler = new ConsoleHandler (){
@Override
protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
super.setOutputStream(System.out);
}
};
La consolehandler prendra un instantané de System.err
lors de la construction. Une option serait d'échanger le flux d'erreur global avec le flux mondial Out, puis de créer la 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);
}
Cela suppose que le code a la permission de modifier le flux d'erreur et qu'aucun autre code d'exécution n'accède au flux d'erreur. En bref, c'est une option mais il y a des alternatives plus sûres.
Si vous utilisez Java Logging, vous pouvez modifier le gestionnaire par défaut:
Par exemple, pour les fichiers: gestionnaire FH = nouveau fichierHandler (nom de fichier); LOGGER.GETLOGER (NOME LOGGER_NAME) .ADDHANDLER (FH);
Si vous souhaitez sortir à un flux, vous pouvez utiliser Streamhandler, je pense que vous pouvez le configurer avec n'importe quel flux de sortie que vous souhaitez, y compris le flux système.
Si vous définissez SETUTUSEPEPHANDLERS (FALSE); Seule cette classe l'a définie. D'autres classes de l'application vont toujours passer à Sterdr.