356 votes

Configurations NLog les plus utiles

Quelles sont les meilleures ou les plus utiles configurations pour la journalisation avec NLog ? (Elles peuvent être simples ou complexes, du moment qu'elles sont utiles).

Je pense à des exemples tels que le renouvellement automatique des fichiers journaux à partir d'une certaine taille, la modification de la présentation (message du journal) en cas d'exception ou non, l'augmentation du niveau du journal une fois qu'une erreur s'est produite, etc.

Voici quelques liens :

3 votes

Voici quelques conseils d'optimisation des performances basés sur des tests : deep-depth.blogspot.com/2014/01/

401voto

wageoghe Points 14676

Certaines d'entre elles entrent dans la catégorie des conseils généraux sur le NLog (ou la journalisation) plutôt que des suggestions de configuration strictes.

Voici quelques liens généraux sur l'exploitation forestière (vous les avez peut-être déjà vus, en partie ou en totalité) :

log4net vs. Nlog

Meilleures pratiques en matière de journalisation

Quel est l'intérêt d'une façade d'exploitation forestière ?

Pourquoi les bûcherons recommandent-ils d'utiliser un bûcheron par classe ?

Utilisez le modèle commun de nommer votre logger basé sur la classe Logger logger = LogManager.GetCurrentClassLogger() . Cela vous donne un haut degré de granularité dans vos loggers et vous offre une grande flexibilité dans la configuration des loggers (contrôle global, par espace de noms, par nom de logger spécifique, etc).

Utilisez des enregistreurs non basés sur des noms de classes lorsque cela est approprié. Vous avez peut-être une fonction pour laquelle vous souhaitez vraiment contrôler la journalisation séparément. Vous avez peut-être des préoccupations transversales en matière de journalisation (journalisation des performances).

Si vous n'utilisez pas la journalisation basée sur les noms de classe, pensez à nommer vos enregistreurs selon une structure hiérarchique (peut-être par domaine fonctionnel) afin de conserver une plus grande flexibilité dans votre configuration. Par exemple, vous pourriez avoir un domaine fonctionnel "base de données", un FA "analyse" et un FA "ui". Chacun de ces domaines peut avoir des sous-domaines. Ainsi, vous pourriez demander des enregistreurs comme celui-ci :

Logger logger = LogManager.GetLogger("Database.Connect");
Logger logger = LogManager.GetLogger("Database.Query");
Logger logger = LogManager.GetLogger("Database.SQL");
Logger logger = LogManager.GetLogger("Analysis.Financial");
Logger logger = LogManager.GetLogger("Analysis.Personnel");
Logger logger = LogManager.GetLogger("Analysis.Inventory");

Et ainsi de suite. Avec les enregistreurs hiérarchiques, vous pouvez configurer l'enregistrement de manière globale (l'enregistreur "*" ou Root), par FA (Database, Analysis, UI) ou par sous-domaine (Database.Connect, etc.).

Les enregistreurs disposent de nombreuses options de configuration :

<logger name="Name.Space.Class1" minlevel="Debug" writeTo="f1" /> 
<logger name="Name.Space.Class1" levels="Debug,Error" writeTo="f1" /> 
<logger name="Name.Space.*" writeTo="f3,f4" />
<logger name="Name.Space.*" minlevel="Debug" maxlevel="Error" final="true" /> 

Voir le Aide NLog pour plus d'informations sur la signification exacte de chacune de ces options. Les éléments les plus remarquables sont probablement la possibilité d'utiliser des règles de journalisation avec caractères génériques, le concept selon lequel plusieurs règles de journalisation peuvent "s'exécuter" pour une seule déclaration de journalisation, et le fait qu'une règle de journalisation peut être marquée comme "finale" afin que les règles suivantes ne s'exécutent pas pour une déclaration de journalisation donnée.

Utilisez le GlobalDiagnosticContext, le MappedDiagnosticContext et le NestedDiagnosticContext pour ajouter un contexte supplémentaire à votre sortie.

Utilisez "variable" dans votre fichier de configuration pour simplifier. Par exemple, vous pouvez définir des variables pour vos mises en page, puis faire référence à la variable dans la configuration cible plutôt que de spécifier directement la mise en page.

  <variable name="brief" value="${longdate} | ${level} | ${logger} | ${message}"/>
  <variable name="verbose" value="${longdate} | ${machinename} | ${processid} | ${processname} | ${level} | ${logger} | ${message}"/>
  <targets>
    <target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${shortdate}.log" />
    <target name="console" xsi:type="ColoredConsole" layout="${brief}" />
  </targets>

Vous pouvez également créer un ensemble "personnalisé" de propriétés à ajouter à une mise en page.

  <variable name="mycontext" value="${gdc:item=appname} , ${mdc:item=threadprop}"/>
  <variable name="fmt1withcontext" value="${longdate} | ${level} | ${logger} | [${mycontext}] |${message}"/>
  <variable name="fmt2withcontext" value="${shortdate} | ${level} | ${logger} | [${mycontext}] |${message}"/>

Ou bien, vous pouvez faire des choses comme créer des moteurs de rendu de mise en page "jour" ou "mois" strictement via la configuration :

  <variable name="day" value="${date:format=dddd}"/>
  <variable name="month" value="${date:format=MMMM}"/>
  <variable name="fmt" value="${longdate} | ${level} | ${logger} | ${day} | ${month} | ${message}"/>
  <targets>
    <target name="console" xsi:type="ColoredConsole" layout="${fmt}" />
  </targets>

Vous pouvez également utiliser les rendus de mise en page pour définir votre nom de fichier :

  <variable name="day" value="${date:format=dddd}"/>
  <targets>
    <target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${day}.log" />
  </targets>

Si vous lancez votre fichier quotidiennement, chaque fichier pourrait être nommé "Monday.log", "Tuesday.log", etc.

N'ayez pas peur d'écrire votre propre moteur de rendu de mise en page. C'est facile et cela vous permet d'ajouter vos propres informations contextuelles au fichier journal via la configuration. Par exemple, voici un layout renderer (basé sur NLog 1.x, pas 2.0) qui peut ajouter le Trace.CorrelationManager.ActivityId au journal :

  [LayoutRenderer("ActivityId")]
  class ActivityIdLayoutRenderer : LayoutRenderer
  {
    int estimatedSize = Guid.Empty.ToString().Length;

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
      builder.Append(Trace.CorrelationManager.ActivityId);
    }

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
    {
      return estimatedSize;
    }
  }

Dites à NLog où se trouvent vos extensions NLog (quel assemblage) comme ceci :

  <extensions>
    <add assembly="MyNLogExtensions"/>
  </extensions>

Utilisez le moteur de rendu de mise en page personnalisé comme ceci :

  <variable name="fmt" value="${longdate} | ${ActivityId} | ${message}"/>

Utilisez des cibles asynchrones :

<nlog>
  <targets async="true">
    <!-- all targets in this section will automatically be asynchronous -->
  </targets>
</nlog>

Et des enveloppes de cibles par défaut :

<nlog>  
  <targets>  
    <default-wrapper xsi:type="BufferingWrapper" bufferSize="100"/>  
    <target name="f1" xsi:type="File" fileName="f1.txt"/>  
    <target name="f2" xsi:type="File" fileName="f2.txt"/>  
  </targets>  
  <targets>  
    <default-wrapper xsi:type="AsyncWrapper">  
      <wrapper xsi:type="RetryingWrapper"/>  
    </default-wrapper>  
    <target name="n1" xsi:type="Network" address="tcp://localhost:4001"/>  
    <target name="n2" xsi:type="Network" address="tcp://localhost:4002"/>  
    <target name="n3" xsi:type="Network" address="tcp://localhost:4003"/>  
  </targets>  
</nlog>

le cas échéant. Consultez la documentation du NLog pour plus d'informations à ce sujet.

Dites à NLog de surveiller et de recharger automatiquement la configuration si elle change :

<nlog autoReload="true" /> 

Il existe plusieurs options de configuration pour faciliter le dépannage de NLog.

<nlog throwExceptions="true" />
<nlog internalLogFile="file.txt" />
<nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" />
<nlog internalLogToConsole="false|true" />
<nlog internalLogToConsoleError="false|true" />

Consultez l'aide de NLog pour plus d'informations.

NLog 2.0 ajoute des wrappers LayoutRenderer qui permettent d'effectuer des traitements supplémentaires sur la sortie d'un layout renderer (comme la suppression des espaces blancs, les majuscules, les minuscules, etc).

N'ayez pas peur d'envelopper le logger si vous voulez isoler votre code d'une dépendance stricte à NLog, mais enveloppez-le correctement. Il y a des exemples sur la façon d'envelopper dans le dépôt github de NLog. Une autre raison d'utiliser le wrap est que vous souhaitez ajouter automatiquement des informations contextuelles spécifiques à chaque message enregistré (en les plaçant dans LogEventInfo.Context).

Il y a des avantages et des inconvénients à envelopper (ou abstraire) NLog (ou tout autre cadre de journalisation d'ailleurs). Avec un peu d'effort, vous pouvez trouver beaucoup d'informations ici sur SO présentant les deux côtés.

Si vous envisagez d'emballer, pensez à utiliser Logging.commun . Cela fonctionne très bien et vous permet de passer facilement à un autre cadre de journalisation si vous le souhaitez. Aussi, si vous envisagez d'envelopper, pensez à la façon dont vous allez gérer les objets de contexte (GDC, MDC, NDC). Common.Logging ne supporte pas actuellement une abstraction pour eux, mais c'est censé être dans la file d'attente des capacités à ajouter.

3 votes

Excellente réponse. Juste une chose à ajouter, ${machine} devrait être ${machinename}. Voir github.com/nlog/NLog/wiki/Layout-Renderers .

2 votes

J'ai créé Common.Logging et ajouté l'abstraction manquante, voir Projet GitHub o NuGet .

0 votes

Je n'ai rien trouvé d'aussi informatif sur nlog dans leur propre documentation, peut-être que je regarde les exemples github de la mauvaise façon ? Qui sait.

66voto

Pat Points 4681

Traiter les exceptions différemment

Nous voulons souvent obtenir plus d'informations lorsqu'il y a une exception. La configuration suivante a deux cibles, un fichier et la console, qui filtrent sur la présence ou non d'informations sur les exceptions. (EDIT : Jarek a publié un article sur un nouvelle méthode pour faire cela dans vNext .)

La clé est d'avoir une cible wrapper avec xsi:type="FilteringWrapper" condition="length('${exception}')>0"

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.mono2.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Warn"
      internalLogFile="nlog log.log"
      >
    <variable name="VerboseLayout" 
              value="${longdate} ${level:upperCase=true} ${message}  
                    (${callsite:includSourcePath=true})"            />
    <variable name="ExceptionVerboseLayout"  
              value="${VerboseLayout} (${stacktrace:topFrames=10})  
                     ${exception:format=ToString}"                  />

    <targets async="true">
        <target name="file" xsi:type="File" fileName="log.log"
                layout="${VerboseLayout}">
        </target>

        <target name="fileAsException"  
                xsi:type="FilteringWrapper" 
                condition="length('${exception}')>0">
            <target xsi:type="File"  
                    fileName="log.log"  
                    layout="${ExceptionVerboseLayout}" />
        </target>

        <target xsi:type="ColoredConsole"
                name="console"
                layout="${NormalLayout}"/>

        <target xsi:type="FilteringWrapper"  
                condition="length('${exception}')>0"  
                name="consoleException">
            <target xsi:type="ColoredConsole" 
                    layout="${ExceptionVerboseLayout}" />
        </target>
    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="console,consoleException" />
        <logger name="*" minlevel="Warn" writeTo="file,fileAsException" />
    </rules>

</nlog>

1 votes

C'est plutôt cool avec la cible séparée et le FilteringWrapper pour formater l'exception. J'ai récemment répondu à une question d'un type qui voulait inclure le rendu de mise en page {exception} dans sa sortie, mais il ne voulait pas obtenir le () qui est apparemment enregistré s'il n'y a PAS d'exception. Cette technique lui conviendrait probablement.

0 votes

+1 Très bien. Je l'avais mis en signet depuis longtemps, et j'ai été renvoyé au "commentaire de Pat" à partir d'une autre question de l'OS concernant une mise en page conditionnelle.

1 votes

Si une exception est enregistrée, elle sera enregistrée deux fois (partie VerboseLayout).

61voto

çağdaş Points 10552

Apparemment, vous pouvez maintenant utiliser NLog avec Growl pour Windows .

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <extensions>
        <add assembly="NLog.Targets.GrowlNotify" />
    </extensions>

    <targets>
        <target name="growl" type="GrowlNotify" password="" host="" port="" />
    </targets>

    <rules>
        <logger name="*" minLevel="Trace" appendTo="growl"/>
    </rules>

</nlog>

NLog with Growl for WindowsNLog trace message with Growl for WindowsNLog debug message with Growl for WindowsNLog info message with Growl for WindowsNLog warn message with Growl for WindowsNLog error message with Growl for WindowsNLog fatal message with Growl for Windows

0 votes

Pouvez-vous me dire ce qu'il faut faire pour une connexion à distance ? le truc fonctionne pour moi pour le localhost mais quand j'ai donné une adresse IP dans l'hôte, ça ne fonctionne pas !

0 votes

@Neel, vous devriez vérifier les paramètres de "Sécurité" dans Growl sur l'ordinateur cible. Vous devez explicitement activer les notifications "LAN" et vous pourriez vouloir configurer un mot de passe (que vous devrez ensuite ajouter à votre cible NLog). Mais je n'ai pas aimé que les notifications à distance apparaissent dans Growl avec une "Origine" de "Machine locale" ; je devrais ajouter l'hôte aux entrées du journal pour savoir d'où proviennent les notifications.

0 votes

J'arrive à faire fonctionner les notifications sur ma machine locale, mais pas à distance. Mes paramètres de sécurité n'ont pas de mot de passe sur growl, donc tout ce que j'ai ajouté c'est l'IP et le port. Mais rien n'est envoyé.

29voto

wageoghe Points 14676

Configurer NLog via XML, mais de manière programmatique

Quoi ? Saviez-vous que vous pouvez spécifier le XML NLog directement à NLog à partir de votre application, au lieu de demander à NLog de le lire à partir du fichier de configuration ? Eh bien, c'est possible. Disons que vous avez une application distribuée et que vous voulez utiliser la même configuration partout. Vous pourriez conserver un fichier de configuration dans chaque emplacement et le maintenir séparément, vous pourriez en maintenir un dans un emplacement central et le pousser vers les emplacements satellites, ou vous pourriez probablement faire beaucoup d'autres choses. Vous pourriez aussi stocker votre XML dans une base de données, l'obtenir au démarrage de l'application et configurer NLog directement avec ce XML (en vérifiant périodiquement s'il a été modifié).

  string xml = @"<nlog>
                   <targets>
                     <target name='console' type='Console' layout='${message}' />
                   </targets>

                   <rules>
                     <logger name='*' minlevel='Error' writeTo='console' />
                   </rules>
                 </nlog>";

  StringReader sr = new StringReader(xml);
  XmlReader xr = XmlReader.Create(sr);
  XmlLoggingConfiguration config = new XmlLoggingConfiguration(xr, null);
  LogManager.Configuration = config;
  //NLog is now configured just as if the XML above had been in NLog.config or app.config

  logger.Trace("Hello - Trace"); //Won't log
  logger.Debug("Hello - Debug"); //Won't log
  logger.Info("Hello - Info");   //Won't log
  logger.Warn("Hello - Warn");   //Won't log
  logger.Error("Hello - Error"); //Will log
  logger.Fatal("Hello - Fatal"); //Will log

  //Now let's change the config (the root logging level) ...
  string xml2 = @"<nlog>
                  <targets>
                     <target name='console' type='Console' layout='${message}' />
                   </targets>

                   <rules>
                     <logger name='*' minlevel='Trace' writeTo='console' />
                   </rules>
                 </nlog>";

  StringReader sr2 = new StringReader(xml2);
  XmlReader xr2 = XmlReader.Create(sr2);
  XmlLoggingConfiguration config2 = new XmlLoggingConfiguration(xr2, null);
  LogManager.Configuration = config2;

  logger.Trace("Hello - Trace"); //Will log
  logger.Debug("Hello - Debug"); //Will log
  logger.Info("Hello - Info");   //Will log
  logger.Warn("Hello - Warn");   //Will log
  logger.Error("Hello - Error"); //Will log
  logger.Fatal("Hello - Fatal"); //Will log

Je ne suis pas sûr de la robustesse de cette méthode, mais cet exemple fournit un point de départ utile pour les personnes qui voudraient essayer de configurer de la sorte.

0 votes

Cela fonctionne très bien... sauf qu'en utilisant cela, il n'est plus possible de reconfigurer dynamiquement le système de journalisation. C'est notamment le cas si vous faites un lien vers un fichier extérieur (include)

2 votes

Cela a fonctionné, même si j'ai dû écrire du "bon" XML en incluant : <?xml version='1.0' encoding='utf-8' ?><nlog xmlns='http://nlog-project.org/schemas/NLog.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>

1 votes

C'est un bon moyen d'accéder à la configuration centralisée. Futurs lecteurs, le xml codé en dur dans cet exemple n'est qu'une démonstration (IMHO), le lire depuis une base de données ou un fichier centralisé pourrait être la véritable implémentation.

23voto

Pat Points 4681

Consignation de niveaux différents selon qu'il y a ou non une erreur

Cet exemple vous permet d'obtenir plus d'informations lorsqu'il y a une erreur dans votre code. Fondamentalement, il met en mémoire tampon les messages et ne sort que ceux d'un certain niveau de journal (par exemple, Warn). sauf si si une certaine condition est remplie (par exemple, s'il y a eu une erreur, le niveau du journal est >= Erreur), il produira plus d'informations (par exemple, tous les messages des niveaux de journal >= Trace). Comme les messages sont mis en mémoire tampon, cela vous permet de recueillir des informations sur ce qui s'est passé. antes de une erreur ou une ErrorException a été enregistrée - très utile !

J'ai adapté celui-ci à partir de un exemple dans le code source . J'ai été déconcerté au début parce que j'ai laissé de côté le AspNetBufferingWrapper (puisque la mienne n'est pas une application ASP) - il s'avère que l'application de l PostFilteringWrapper nécessite une cible tamponnée. Notez que le target-ref utilisé dans l'exemple ci-dessus ne peut pas être utilisé dans NLog 1.0 (j'utilise 1.0 Refresh pour une application .NET 4.0) ; il est nécessaire de placer votre cible à l'intérieur du bloc wrapper. Notez également que la syntaxe logique (c.-à-d. les symboles plus grand que ou moins grand, < et >) doit utiliser les symboles, et non les caractères d'échappement XML pour ces symboles (c.-à-d. &gt; y &lt; ), sinon le NLog se trompe.

app.config :

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
    </configSections>

    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          throwExceptions="true" internalLogToConsole="true" internalLogLevel="Warn" internalLogFile="nlog.log">
        <variable name="appTitle" value="My app"/>
        <variable name="csvPath" value="${specialfolder:folder=Desktop:file=${appTitle} log.csv}"/>

        <targets async="true">
            <!--The following will keep the default number of log messages in a buffer and write out certain levels if there is an error and other levels if there is not. Messages that appeared before the error (in code) will be included, since they are buffered.-->
            <wrapper-target xsi:type="BufferingWrapper" name="smartLog">
                <wrapper-target xsi:type="PostFilteringWrapper">
                    <!--<target-ref name="fileAsCsv"/>-->
                    <target xsi:type="File" fileName="${csvPath}"
                    archiveAboveSize="4194304" concurrentWrites="false" maxArchiveFiles="1" archiveNumbering="Sequence"
                    >
                        <layout xsi:type="CsvLayout" delimiter="Tab" withHeader="false">
                            <column name="time" layout="${longdate}" />
                            <column name="level" layout="${level:upperCase=true}"/>
                            <column name="message" layout="${message}" />
                            <column name="callsite" layout="${callsite:includeSourcePath=true}" />
                            <column name="stacktrace" layout="${stacktrace:topFrames=10}" />
                            <column name="exception" layout="${exception:format=ToString}"/>
                            <!--<column name="logger" layout="${logger}"/>-->
                        </layout>
                    </target>

                     <!--during normal execution only log certain messages--> 
                    <defaultFilter>level >= LogLevel.Warn</defaultFilter>

                     <!--if there is at least one error, log everything from trace level--> 
                    <when exists="level >= LogLevel.Error" filter="level >= LogLevel.Trace" />
                </wrapper-target>
            </wrapper-target>

        </targets>

        <rules>
            <logger name="*" minlevel="Trace" writeTo="smartLog"/>
        </rules>
    </nlog>
</configuration>

0 votes

Dans certaines versions de NLog (pour mono et je pense 2.0), cela provoque une StackOverflowException, mais pas dans d'autres (rafraîchissement de NLog 1).

0 votes

En ce qui concerne le débordement - Il semble être dû uniquement au fait que la mise en page est de type CSV - si je fais une mise en page normale, il n'y a pas de problème.

0 votes

A quoi sert la target-ref fileAsCsv, là ? J'essaie de faire fonctionner cet exemple avec NLog v2.0.0.2000, mais sans succès jusqu'à présent.

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