12
votes

"Désactiver" le flux de sortie

J'utilise une bibliothèque égarée qui, malheureusement, imprime des informations sur system.out (ou occasionnellement system.err ). Quel est le moyen le plus simple d'empêcher cela?

J'ai réfléchi à la création d'un flux de sortie à la mémoire, remplacez system.out et err avant chaque appel à l'une des méthodes de trouble, restaurez-les plus tard, et ignorez simplement le tampon du flux créé. Y a-t-il une voie plus facile et plus élégante?

Edit: Je ne veux pas rediriger toutes les sorties - c'est facilement accompli. Je veux seulement ignorer la sortie potentiellement générée par certains appels de bibliothèque.


0 commentaires

4 Réponses :


1
votes
File file  = new File(filename);
PrintStream printStream = new PrintStream(new FileOutputStream(file));
System.setOut(printStream);

3 commentaires

Alors vient de le jeter dans un fichier aléatoire? Et plus tard supprimer le fichier? Cela semble un peu gaspillé, n'est-il pas préférable de le jeter à un tampon en mémoire?


@OAK Si vous n'êtes pas intéressé par les messages - Que diriez-vous d'étendre PrintStream et d'ignorer quoi que ce soit (implémentations vides)?


Le sous-classement avec une implémentation vide est en fait la meilleure idée jusqu'à présent - très simple, assez court avec une classe anonyme.



1
votes

Il y a 2 façons. 1. Le moyen le plus simple consiste à exécuter votre programme et à rediriger toute sortie sur / dev / null (si vous êtes sur UNIX) ou au fichier spécial qui sera supprimé (pour Windows) De cette façon, c'est simple mais cela signifie que toute votre sortie ne va à rien. Si votre programme utilise stdout pour de bonnes choses, vous ne pouvez pas utiliser de cette façon.

  1. Vous pouvez définir stdout à l'aide de Java API.

    système.setout (OUT) System.setERR (OUT)

    Vous pouvez désormais implémenter votre propre sortie de sortie: xxx

    Ceci est meilleur car vous pouvez filtrer la sortie non pertinente et imprimer de bonnes informations. < / p>


2 commentaires

L'envoi de sortie à / dev / null est une mauvaise idée, car elle forcerait un changement de contexte et a un impact très grave sur la performance. Je le prête à la main dans un centre de référence.


La création de la trace de la pile d'une exception est lente, vous devez donc profiler l'application si vous utilisez ce code. L'appel à Nouveau lanceur () peut facilement devenir un goulot d'étranglement si le programme imprime quelque chose pendant le fonctionnement normal. De plus, vous ne pouvez pas savoir que lesquels des oligo-éléments de la pile ont été appelés, car le nombre de cadres de pile dépend de la méthode d'écriture appelée à l'origine, de sorte que certains itérateurs sont nécessaires.



4
votes

Un moyen de se débarrasser de ces impressions indésirables de manière permanente em> serait d'utiliser la manipulation de Bytecode em> pour supprimer les instructions d'impression de la bibliothèque gênante. Cela peut être fait par exemple en utilisant ASM (ou l'un des autres niveaux plus haut et plus facile à utiliser AOP frameworks).

Vous pouvez le faire à l'exécution ou en tant que fonctionnement ponctuel de réécriture les fichiers de classe de la bibliothèque. Reportez-vous à la documentation de l'ASM pour savoir comment. Voici une preuve de concept. Ce qu'il fait, c'est qu'il remplace toutes les références à system.out code> avec une référence à un imprimanteam code> qui ne fait rien. P>

d'abord les tests. Ils utilisent des classes utilitaires de mon projet pour vous aider à tester les transformations de byTecode (test nécessaire pour créer un chargeur de classe personnalisé et appliquer les transformations de bytecode sur la classe de droite mais pas d'autres classes). p> xxx pré>

puis la mise en œuvre. Veuillez noter que vous ne devriez pas utiliser ce code sans la compréhension d'abord. Ne Programme par coïncidence . P>

class SilentSystem {
    public static final PrintStream out = new PrintStream(new OutputStream() {
        public void write(int b) {
        }
    });
}

class RemoveCallsToSystemOut extends ClassAdapter {

    public RemoveCallsToSystemOut(ClassVisitor cv) {
        super(cv);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        return new MyMethodAdapter(super.visitMethod(access, name, desc, signature, exceptions));
    }

    private static class MyMethodAdapter extends MethodAdapter {
        public MyMethodAdapter(MethodVisitor mv) {
            super(mv);
        }

        @Override
        public void visitFieldInsn(int opcode, String owner, String name, String desc) {
            if (opcode == Opcodes.GETSTATIC
                    && owner.equals("java/lang/System")
                    && name.equals("out")
                    && desc.equals("Ljava/io/PrintStream;")) {
                super.visitFieldInsn(opcode, "net/orfjackal/dimdwarf/aop/SilentSystem", name, desc);
            } else {
                super.visitFieldInsn(opcode, owner, name, desc);
            }
        }
    }
}


3 commentaires

Je cherchais une méthode simple :) Encore, merci, c'est très intéressant.


La simplicité peut dépendre du point de vue. ;) Cette méthode est sûrement avancée, mais après traitement du pot une fois, la bibliothèque sera très simple à utiliser. L'autre méthode d'utilisation du système.setout d'autre part est plus facile à apprendre, mais peut causer un comportement inattendu au moment de l'exécution; Il peut facilement empêcher d'imprimer certaines choses que vous aimeriez être imprimées et que de nombreux cas d'angles doivent prendre en compte, tels que la concurrence et l'impression à partir de threads multiples, des exceptions projetées par la bibliothèque ou si vous souhaitez ne cacher que certaines des les choses imprimées par la bibliothèque et montrent aux autres.


Oh oui. Si la bibliothèque est open source, vous avez la possibilité de supprimer les instructions d'impression de la source et de le recompiler.



16
votes

J'ai fini par faire quelque chose comme:

PrintStream out = System.out;
System.setOut(new PrintStream(new OutputStream() {
    @Override public void write(int b) throws IOException {}
}));
try {
    <library call>
} finally {
    System.setOut(out);
}


0 commentaires