Comment faire du logging performant ?

Histoire de gagner du temps

a marqué ce sujet comme résolu.

Salut,

Voilà, en gros j'ai besoin de parcourir une énorme quantité d'informations et d'y appliquer des algos. Seulement je voudrais pour chaque information avoir quelques retours de fonctions et ainsi pouvoir débuguer(et vérifier si tout ce passe bien). Je penses surement utiliser du java ou du python. Par contre, c'est le première fois où je me retrouve "sérieusement" confronté au fait qu'afficher une information à l'écran(via print/System.out.print) est extrêmement lent. Je me demander quelle est la méthode la plus performante ?

J'en ai pensé à 3 :

  • Ecrire dans un fichiers (mais j'imagine que c'est plus lent encore)

  • Utiliser les systèmes de Logging (j'en ai jamais utilisé et donc je sais pas si c'est astucieux)

  • Faire du Threading, afin de séparer l'affichage du reste, ca me semble une bonne idée, mais j'ai peur que ça fasse une énorme latence entre ce que je vois et ce qu'il fait, et au final, que je perde autant de temps à ce que le thread finisse sa tâche.

Donc voilà je voudrais savoir quelles techniques faut-il employer dans ce genre de cas ?

Merci :)

+0 -0

Si c'est juste des information de debug, le Logging est à mon avis la meilleure solution.

Cela a (notamment) les avantages suivants:

  • Activation/désactivation des logs au besoin et à chaud (sans redémarrer ton programme).
  • Redirection vers la sortie standard ou un fichier au choix (modifiable dynamiquement également).
  • Filtrage par niveau (importance/gravité) de message (typiquement fine, debug, info, warning, severe).

Exemple d'utilisation (en java) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/** Logger (dans un attribut static pour l'avoir facilement sous la main) */
private static Logger   lg  = Logger.getLogger(App.class.getName());

// Exemple d'utilisation
T.info("Saving updated dictionaries");
for (final Entry<String, Dictionary> dictionary : customDictionaries.entrySet()) {
    if (activeDictionaries.contains(dictionary.getValue()) && dictionary.getValue().isUpdated()) {
        // Pour les log susceptible de sortir souvent (ou de niveau fin), vérifier le niveau de log avant d'écrire le message pour éviter de dégrader les performances en utilisation "normale"
        if (lg.isLoggable(Level.FINE)) {
            lg.fine("Saving dictionary " + dictionary.getKey() + " because it has been updated in the last session");
        }
        try {
            dictionary.getValue().save();
            if (lg.isLoggable(Level.INFO)) {
                lg.info("Dictionary successfully saved");
            }
        } catch (final IOException e) {
            lg.warning("The dictionary file " + dictionary.getKey() + " could not be saved: "
                    + e.getMessage());
        }
    }
}
activeDictionaries.clear();

Une mécanique similaire doit exister en Python (le contraire m'étonnerait), mais je ne connais pas ce langage.

Ton code est-t-il déjà écrit ? L'affichage d'informations à l'écran est-il vraiment le goulot d'étranglement ? Que dit le profiler ?

GuilOooo

Il n'est pas encore écrit, mais je suis sûr que ca va ralentir, je vais avoir besoin d'analyser des centaines(voir des milliers) d'informations, et d'y appliquer quelques calculs dessus. Pour avoir fait l'expérience en java et python, dès qu'il y a déjà plusieurs dizaines de lignes à afficher, on perd pas mal de temps.

Kje & AlexRNL -> Oui je mettais déjà renseigner sur le logging en java et en python mais sachant pas ce que ça vaut j'avais pas essayé :)

Ce genre d'info pourrait t'être utile.

En gros, soit tu utilises une bibliothèque de logging qui sait formater les données et qui ne le fera que si nécessaire, soit tu vérifies que le message sera bien loggé avant de le formater, histoire d'éviter de formater des messages ce qui peut parfois s'avérer coûteux.

+0 -0

Ton code est-t-il déjà écrit ? L'affichage d'informations à l'écran est-il vraiment le goulot d'étranglement ? Que dit le profiler ?

GuilOooo

Il n'est pas encore écrit, mais je suis sûr que ca va ralentir, je vais avoir besoin d'analyser des centaines(voir des milliers) d'informations, et d'y appliquer quelques calculs dessus. Pour avoir fait l'expérience en java et python, dès qu'il y a déjà plusieurs dizaines de lignes à afficher, on perd pas mal de temps.

Tick

Bien sûr que ça va ralentir ton programme. La question est de savoir à quel point ? Avant d'avoir fait le test tu ne pourras pas le savoir, fait des tests de performances avec et sans les logs activés pour comparer.

D'autant plus qu'il est rarement nécessaire de logger autant d'information pur une version livrée de ton programme (sauf en cas de bug à investiguer…). Il faut réfléchir à quelles informations tu aura besoin si tu dois analyser un bug dans ton logiciel, afin d'éviter au maximum de te retrouver avec des fichiers de plusieurs milliers de lignes à investiguer.

En tout cas, aujourd'hui, je ne me vois plus réaliser un seul logiciel sans logs. Ils sont nécessaires non seulement pour le développement de celui-ci mais aussi son intégration dans un système. Par ailleurs, un effet de bord d'avoir un code correctement loggé, est qu'il est plus facile à (re)lire : c'est un bon complément aux commentaires dans le code.

Kje & AlexRNL -> Oui je mettais déjà renseigner sur le logging en java et en python mais sachant pas ce que ça vaut j'avais pas essayé :)

Tick

C'est en forgeant qu'on devient forgeron.

Lu'!

Je vote pour les solutions standard de logging, rien que pour la flexibilité que ça apporte en terme de sélection de ce que l'on veut logger ou pas en fonction d'une configuration.

Sinon une petite note :

  • Ecrire dans un fichiers (mais j'imagine que c'est plus lent encore)

Tick

Dans la majorité des cas, ce sera au contraire beaucoup plus rapide (encore plus vrai si tu tournes sur un SSD).

C'est en forgeant qu'on devient forgeron.

AlexRNL

Sans rapport avec la choucroute : c'est également en martelant qu'on devient marteau.

Je confirme, logger dans un fichier est 100 fois plus rapide que de logger directement dans la console, du moment que le flux est correctement bufférisé (en java, passer par BufferedWriter ou BufferedOutputStream avant PrintStream ou PrintWriter). Observé sous windows comme sous linux et approuvé sur des volumes de l'ordre de 10 Mo mais on constate la différence bien avant (dès qu'on print plus que 200 ou 300 Ko on y gagne déjà clairement). Le simple fait de rediriger System.out/err avec l'opérateur > du shell change déjà énormément.

Sinon j'ignorais qu'il y avait un truc tout fait dans la bibliothèque standard de java; je vais m'empresser de l'utiliser et je conseille de faire de même.

+0 -0

Je pense à un truc, si tu dois logguer vraiment rapidement (plus rapidement que le permet ton disque dur), de manière temporaire et que tu tournes sous un Unix, tu peux faire un système de fichier temporaire sur mémoire vive et logguer dessus, ça t'offrira des débits de l'ordre du Go/s.

Tout comme QuentinC, j'ignorais qu'il y avait une bibliothèque standard Java pour les logs ! J'ai vu une ancienne application utilisée la bibliothèque Log4J. Ca permet de faire du log, de configurer quelques trucs (création d'un autre fichier à partir de X Mo par exemple) et aussi de faire différentes sorties (fichier texte, fichier HTML en mode "tableau" (ça fait de belles sorties parfois)).

Mais bon, ça doit pas être nécessaire pour faire ce que tu veux :p

Tout comme QuentinC, j'ignorais qu'il y avait une bibliothèque standard Java pour les logs ! J'ai vu une ancienne application utilisée la bibliothèque Log4J. Ca permet de faire du log, de configurer quelques trucs (création d'un autre fichier à partir de X Mo par exemple) et aussi de faire différentes sorties (fichier texte, fichier HTML en mode "tableau" (ça fait de belles sorties parfois)).

Mais bon, ça doit pas être nécessaire pour faire ce que tu veux :p

Nirv

Qui peut le plus, peut le moins. Il n'est pas obligé d'utiliser les logs tournant pour son application. L'API de logging standard de Java suffit pour la plupart des cas. Je suis d'ailleurs en train de rédiger un tutoriel là dessus :)

Quand je disais "ça doit pas être nécessaire", je voulais dire que l'API standard suffisait effectivement ! J'évoquais Log4J parce que je connaissais un peu et si ça pouvait éventuellement intéressé :D

Ah, sympa un tuto là dessus, ça m'intéresserait :p

J'aurais vraiment tendance à te conseiller slf4j.

L'API standard date de Java 1.4, elle est vieillotte, les niveau de logs sont franchement surprenants (FINE, FINER, FINEST ???).

C'est pas franchement agréable à configurer (déclaration de tes appenders dans le code, quand tu veux changer quelque chose il faut aller bidouiller…). N'accepte que des Strings comme je le disais plus haut, ce qui t'oblige à faire attention que le message sera effectivement loggé pour ne pas faire de formatage inutile et coûteux.

SLF4J est une API qui joue le rôle de pont entre la déclaration de tes logs log.debug(...) et l'implémentation choisie (log4j ou autres).

Honnêtement, je pense que tu devrais t'orienter vers slf4j, je ne sais pas ce que les autres développeurs Java du site en pense, mais à mon avis tant qu'à faire d'apprendre un truc nouveau, autant aller voir de ce côté là.

+0 -0

Je pense à un truc, si tu dois logguer vraiment rapidement (plus rapidement que le permet ton disque dur), de manière temporaire et que tu tournes sous un Unix, tu peux faire un système de fichier temporaire sur mémoire vive et logguer dessus, ça t'offrira des débits de l'ordre du Go/s.

Bien garder à l'esprit quand même que si pour une raison ou une autre tu dois reboot, adieu le log. Suivant l'application, ça peut être important d'être fiable à toute épreuve ou presque (et pour les crash disques il y a les RAID)

+0 -0

Je pense à un truc, si tu dois logguer vraiment rapidement (plus rapidement que le permet ton disque dur), de manière temporaire et que tu tournes sous un Unix, tu peux faire un système de fichier temporaire sur mémoire vive et logguer dessus, ça t'offrira des débits de l'ordre du Go/s.

Bien garder à l'esprit quand même que si pour une raison ou une autre tu dois reboot, adieu le log. Suivant l'application, ça peut être important d'être fiable à toute épreuve ou presque (et pour les crash disques il y a les RAID)

QuentinC

C'est pour ça que j'ai indiqué "de manière temporaire". Ensuite, il y a aussi moyen de l'utiliser comme un cache, et que cet espace mémoire soit dupliqué sur le disque de manière différée.

L'API standard date de Java 1.4, elle est vieillotte, les niveau de logs sont franchement surprenants (FINE, FINER, FINEST ???).

Javier

Pas plus surprenant que les niveaux des autres API, tout est une question d'habitudes.

C'est pas franchement agréable à configurer (déclaration de tes appenders dans le code, quand tu veux changer quelque chose il faut aller bidouiller…). N'accepte que des Strings comme je le disais plus haut, ce qui t'oblige à faire attention que le message sera effectivement loggé pour ne pas faire de formatage inutile et coûteux.

Javier

Je comprends pas bien ce que tu veux dire par là. J'utilise régulièrement l'API, et tu peux changer l'appender via le logging.properties, sans aller bidouiller le code. Pour moi, cette API suffit largement pour les besoin de la plupart des développeurs.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte