50 votes

Implémentation de classe de journalisation sécurisée pour les threads

Est-ce que ce qui suit serait la bonne façon d'implémenter une classe de journalisation thread-safe assez simple?

Je sais que je ne ferme jamais explicitement le TextWriter , serait-ce un problème?

Lorsque j'ai initialement utilisé la méthode TextWriter.Synchronized , cela ne semblait pas fonctionner jusqu'à ce que je l'initialise dans un constructeur statique et que je le fasse en lecture seule comme ceci:

 public static class Logger
{
    static readonly TextWriter tw; 

    static Logger()
    {
        tw = TextWriter.Synchronized(File.AppendText(SPath() + "\\Log.txt")); 
    }

    public static string SPath()
    {
        return ConfigManager.GetAppSetting("logPath"); 
    }

    public static void Write(string logMessage)
    {
        try
        {
            Log(logMessage, tw);
        }
        catch (IOException e)
        {
            tw.Close();
        }
    }

    public static void Log(string logMessage, TextWriter w)
    {
        w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
            DateTime.Now.ToLongDateString());
        w.WriteLine("  :");
        w.WriteLine("  :{0}", logMessage);
        w.WriteLine("-------------------------------");

        // Update the underlying file.
        w.Flush();
    }
}
 

93voto

x0n Points 26002

Je vais prendre une approche complètement différente que les autres réponses et supposons que vous voulez vraiment apprendre à mieux écrire le thread courant de code, et ne sont pas à la recherche pour la 3ème partie suggestions de nous (même si on peut effectivement se retrouver à l'aide de l'un.)

Comme d'autres l'ont dit, vous êtes la création d'un thread-safe TextWriter ce qui signifie que les appels à WriteLine sont thread-safe, cela ne signifie pas qu'un tas d'appels d' WriteLine vont être effectuée comme une opération atomique. Par cela je veux dire qu'il n'y a aucune garantie que les quatre WriteLine appels vont se produire dans la séquence. Vous pouvez avoir un "thread-safe" TextWriter, mais vous n'avez pas thread-safe Logger.Log méthode ;) Pourquoi? Parce qu'à tout moment au cours de ces quatre appels, un autre thread peut décider de faire appel Log également. Cela signifie que votre WriteLine des appels de la synchronisation. Le moyen de résoudre ce problème est d'utiliser un lock énoncé comme suit:

private static readonly object _syncObject = new object();

public static void Log(string logMessage, TextWriter w)    {
   // only one thread can own this lock, so other threads
   // entering this method will wait here until lock is
   // available.
   lock(_syncObject) {
      w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
          DateTime.Now.ToLongDateString());
      w.WriteLine("  :");
      w.WriteLine("  :{0}", logMessage);
      w.WriteLine("-------------------------------");
      // Update the underlying file.
      w.Flush();
   }
}

Ainsi, vous avez maintenant un "thread-safe" TextWriter ET un "thread-safe" Logger.

Un sens?

5voto

Reed Copsey Points 315315

Tout en appelant TextWriter.Synchronisé permettra de protéger d'une instance unique d' TextWriter, il ne sera pas synchroniser votre écrit de sorte qu'un "Journal" appel reste ensemble à l'intérieur du fichier.

Si vous appelez Write (ou Log à l'aide de l'interne TextWriter exemple) à partir de plusieurs threads, la personne WriteLine des appels peuvent être imbriquées, ce qui rend votre date et l'heure timbres inutilisable.

Je serais personnellement utiliser un tiers solution d'enregistrement qui existe déjà pour cela. Si ce n'est pas une option, la synchronisation de vous-même (même avec un simple verrou) sera probablement plus utile que d'utiliser le cadre de l' TextWriter.Synchronized wrapper.

2voto

GlennFerrieLive Points 4524

Vous devriez regarder dans cette classe (partie de .NET 2.0), pas besoin de "créer" votre propre enregistreur. vous permet de vous connecter à un fichier de texte, d'événements, etc.

http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource.aspx

Votre "Journal" la méthode peut ressembler à quelque chose comme ceci (en supposant qu'il existe une intermal membre de la variable appelée 'traceSource'):

    public void Log(TraceEventType eventType, string message)
    {
        this.traceSource.TraceEvent(eventType, 0, message);
        this.traceSource.Flush();
    }

L'appui de cette est une section de configuration que les noms de la TraceSource et a certains paramètres de configuration. Il est supposé que lorsque vous construisez un TraceSource dans votre enregistreur vous sont instanciation avec l'une des sources de suivi nommée dans la config.

<system.diagnostics>
<sources>
  <source name="Sample" switchValue="Information,ActivityTracing">
    <listeners>
      <add name="file"
         initializeData="C:\temp\Sample-trace.log"
         traceOutputOptions="DateTime"
         type="System.Diagnostics.TextWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    </listeners>
  </source>
</sources>

Aussi, ne pas faire de votre enregistreur de statique. Au lieu de cela, l'utilisation d'Enterprise Library 5.0 Unité pour l'Injection de Dépendances / CIO.

Espérons que cette aide!

0voto

Dave R. Points 4621

Si vous êtes à la recherche d'une méthode simple de instrumentant votre code, l'installation existe déjà à l'intérieur .NET:

http://msdn.microsoft.com/en-us/library/system.diagnostics.trace.aspx

En outre, des outils de tiers va vous donner des solutions robustes pour l'exploitation forestière; les exemples incluent log4net, nLog, et la Bibliothèque d'Entreprise.

Je vous recommande vraiment de ne pas réinventer la roue sur ce point :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X