IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Forms Discussion :

[c# Multithreadé]Gestion de logs


Sujet :

Windows Forms

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Août 2006
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 37
    Par défaut [c# Multithreadé]Gestion de logs
    Bonjour à tous.

    Ma question est peut-être assez classique, mais la plupart des réponses me semblent pour le moins "lourdes". En effet, j'ai besoin de tracer les évènements dans un client lourd qui a de "nombreux" threads asynchrones. Or, l'écriture dans un fichier de log unique est problématique, car, de temps en temps, on rencontre des "locks" du même fichier entre threads. De fait, j'ai juste fait ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    GestionFichier() { }
     
            //Creation et ecriture du fichier de log
            public void logger(string ligne)
            {
                try
                {
                    StringBuilder line = new StringBuilder();
                    StreamWriter oStreamWriter;
                    while ((oStreamWriter = TryExclusiveOpen(fichierLog)) == null) ;
                    line.AppendFormat(@"{0}:{1}", DateTime.Now.ToString(), ligne);
                    oStreamWriter.WriteLine(line.ToString());
                    oStreamWriter.Close();
                }
                //Gestion de toutes les exceptions
                catch (Exception ex)
                {
                    GestionFichier.getInstance().erreur("GestionFichier > logger > Exception > " + ex.Message);
                    GestionFichier.getInstance().logger("GestionFichier > logger > Exception > " + ex.Message);
                    msg = ex.Message;
                    //msg = GestionFichier.getInstance().getMessage("2");
                    MessageBox.Show(msg, Constantes.msg_erreur, System.Windows.Forms.MessageBoxButtons.OK);
                    System.Environment.Exit(0);
                    //fenetreException = new FenetreException(msg, ex);
                    //fenetreException.Show();
                }
            }
            private StreamWriter TryExclusiveOpen(String filename)
            {
                try
                {
                    StreamWriter oStreamWriter = new StreamWriter(filename, true);
                    return oStreamWriter;
                }
                catch
                {
                    return null;
                }
            }
    Ok, c'est assez crade (pour tester uniquement), mais je cherche à optimiser le tout.
    1) Parce que je ne fais pas confiance à une boucle infinie pour faire patienter le thread à l"écriture
    2) Parce que je ne suis pas sûr que cela ne peut pas provoquer de bug débile.

    Donc:
    1° j'ai vu de la gestion de log en threadé sur le net. Est-ce malin/efficace? Me concernant, je suis un peu perplexe de laisser un thread tourner que pour faire quelques écritures de logs.
    2° Y a-t-il un moyen plus propre de gérer le lock de fichier, même temporairement?

    Toute proposition est bienvenue

  2. #2
    Membre Expert
    Avatar de GuruuMeditation
    Homme Profil pro
    .Net Architect
    Inscrit en
    Octobre 2010
    Messages
    1 705
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net Architect
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2010
    Messages : 1 705
    Par défaut
    A tester pour être sûr, mais je pense que log4net est thread safe (il utilise des lock). Sinon tu peux aussi utiliser un lock.(lock code, pas lock fichier)

  3. #3
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 048
    Par défaut
    Or, l'écriture dans un fichier de log unique est problématique, car, de temps en temps, on rencontre des "locks" du même fichier entre threads
    C'est un peu la problématique de base du multithreading la gestion du lock pour les ressources qui ne peuvent pas être partagées...

    j'ai vu de la gestion de log en threadé sur le net. Est-ce malin/efficace? Me concernant, je suis un peu perplexe de laisser un thread tourner que pour faire quelques écritures de logs.
    Au final la programmation de type multithread, c'est un peu comme si tu as une usine avec un tas de type qui font chacun une tâche précise au lieu d'avoir un type qui court partout.


    Est-ce que c'est plus propre d'avoir à gérer 30 types qui essaye d'écrire sur un tableau et même temps ou d'avoir une personne qui fait que de reporter ce que les 30 autres lui communique.

    Un thread qui se tourne les pouces pendant 98% du temps c'est pas un problème en multithread. La gestion du partage des ressources c'est plus le problème du Framework...

    2° Y a-t-il un moyen plus propre de gérer le lock de fichier, même temporairement?
    Sauf erreur il y a la possibilité de mettre un lock sur une variable depuis un thread et de tester le lock (voir d'attendre sa disponibilité) avant d'effectuer l'opération. Ce qui est beaucoup plus propre que d'essayer et de voir si ça plante...

    Je te recommande chaudement la lecture suivante:

    http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

  4. #4
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    @Magellan94
    L'approche classique est de synchroniser l'accès aux méthodes. Concrètement, tu places tout le code de la méthode "logger" dans un bloc "lock" (voir documentation de "lock" sur MSDN). Ce verrouillage va garantir que si un thread A est déjà en train d'exécuter "logger", l'appel de cette méthode par un thread B va mettre B en pause jusqu'à ce que A ait terminé son appel à "logger".

    L'autre approche à laquelle tu semblais songer est celle d'un "agent", c'est à dire d'un thread dédié à une activité (ici la gestion du log). Concrètement, un appel à "logger" ne ferait que mettre une ligne dans une file d'attente (et éventuellement réveiller le thread de logging si celui-ci était assoupi) tandis qu'un thread dédié vide régulièrement cette file d'attente pour réaliser l'écriture. Pour ça tu auras besoin de deux composants :
    * Une file d'attente thread-safe (il y en a une dans System.Collections.Concurrent) ou une file d'attente privée dont l'accès sera gardé par un verrou (lock).
    * Un WaitEventHandle qui permet à un thread de se mettre en sommeil s'il n'a rien à faire (event.WaitOne()) et à un autre thread de le réveiller (event.Set()). Tu gardes le modèle d'une boucle infinie mais ton thread est endormi quand il n'a rien à faire.

    Personnellement j'aime beaucoup les agents, j'en mets souvent en place. Toutefois, l'approche traditionnelle est ici simple à mettre en oeuvre et il ne semble pas d'y avoir de raison d'utiliser un agent.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Août 2006
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 37
    Par défaut
    Merci pour les deux solutions!

    J'ai opté, en test, opté pour le "lock" de l'accès (via la fonction suggérée, et grâce à pas mal d'exemples sur le net). De fait, je n'ai pour l'heure rencontré aucun souci, d'autant que le seul souci qui pouvait être rencontré était un accès concurrent par deux threads. J'avais "contourné" en faisant une forme de while qui tentait d'accéder en ouverture/écriture au fichier et à chaque échec, relançait le test. C'était provisoire, crade, et j'ai décidé d'implémenter quelque chose de plus conventionnel et acceptable!

    Là, je vais valider par une recette complète le bon fonctionnement pour ma situation (et également valider que j'ai bien utilisé la bonne façon de faire).

    Encore une fois, merci pour les renseignements, je ne suis pas encore rôdé aux threads

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Août 2006
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 37
    Par défaut
    Voilà le code...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    //Singleton
            public static GestionFichier getInstance()
            {
                lock (_classLock)
                {
                    if (null == _Logger)
                    {
                        _Logger = new GestionFichier();
                    }
                }
                return _Logger;
            }
     
     
    		public void logger(string ligne)
    		{
                StringBuilder line = new StringBuilder();
                try
    			{
    				if (_Output==null)
    				{
     
                        _Output = new System.IO.StreamWriter(fichierLog, true, System.Text.UnicodeEncoding.Default);
                        line.AppendFormat(@"{0}:{1}", DateTime.Now.ToString(), ligne);
    				}
                    _Output.WriteLine(line.ToString());
    				if (_Output != null)
    				{
    					_Output.Close(); 
    					_Output = null;
    				}
    			}
    			catch(Exception ex)
    			{
                    string msg = ex.Message;
                    MessageBoxTopMost.Show(msg, Constantes.msg_erreur, System.Windows.Forms.MessageBoxButtons.OK);
                    System.Environment.Exit(0);
     
    			}
    		}
     
    		public static void closeLog()
    		{
    			try
    			{
    				if (_Output != null)
    				{
    					_Output.Close();
    					_Output = null;
    				}
    			}
    			catch(Exception ex)
    			{
    				Console.WriteLine(ex.Message,new object[0]);
    			}
    		}
    Seulement, je me retrouve parfois avec un pop d'erreur mentionnant que le fichier est en cours d'accès. aurais je loupé quelque chose?

Discussions similaires

  1. Quel SGBD a une bonne gestion des LOGs ?
    Par joker vb dans le forum Décisions SGBD
    Réponses: 12
    Dernier message: 03/04/2008, 17h17
  2. [Source][Ocx]composant gestion des logs
    Par Delbeke dans le forum Vos contributions VB6
    Réponses: 4
    Dernier message: 23/12/2007, 16h42
  3. [Multithread] Gestion des connexions
    Par Wookai dans le forum Accès aux données
    Réponses: 2
    Dernier message: 22/11/2007, 22h43
  4. Gestion fichiers logs - file_put_contents ?
    Par Merfolk dans le forum Langage
    Réponses: 1
    Dernier message: 31/10/2007, 20h26
  5. Gestion des .log sous Oracle
    Par SANOORA dans le forum Administration
    Réponses: 10
    Dernier message: 08/11/2004, 09h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo