web-dev-qa-db-fra.com

Comment enregistrer un champ personnalisé dans NLog dans la base de données?

J'utilise actuellement NLog sur de nombreux projets. Sur certains, je me connecte à une base de données.

Voici ce que j'aimerais faire:

CREATE TABLE [dbo].[NLogEntries](
  [Id] [bigint] IDENTITY(1,1) NOT NULL,
  [Origin] [nvarchar](100) NOT NULL,
  [LogLevel] [nvarchar](20) NOT NULL,
  [Message] [nvarchar](3600) NOT NULL,
  [CreatedOn] [datetime] NOT NULL,
  [OrderId] [int] NULL --Custom field!
)

Et NLog.config avec cette cible:

<target type="Database" name="database" connectionstring="Server=localhost;Database=NLog;Trusted_Connection=True;">
  <commandText>
    INSERT INTO NLogEntries ([Origin], [Message], [LogLevel],[CreatedOn],[OrderId]) VALUES (@Origin,@Message,@LogLevel,@Date, @OrderId);
  </commandText>
  <parameter name="@Date" layout="${date}"/>
  <parameter name="@Origin" layout="${callsite}"/>
  <parameter name="@LogLevel" layout="${level}"/>
  <parameter name="@message" layout="${message}"/>
  <parameter name="@OrderId" layout="${orderId}"/> <!-- custom field! -->
</target>

Et puis connectez quelque chose comme ceci:

var logger = LogManager.GetCurrentClassLogger();
var orderId = 123;
logger.Debug("What is going on here", orderId);

Existe-t-il un bon moyen de le faire et de continuer à utiliser NLog? Ou dois-je faire rouler mon propre enregistreur et ignorer NLog lorsque ce sont les exigences?

41
Kjensen

Plutôt que d'utiliser GDC, qui concerne les données statiques globales et échoue lors de la journalisation simultanée, il est préférable d'utiliser EventProperties-Layout-Renderer qui permet de transmettre des propriétés personnalisées spécifiques à l'événement

LogEventInfo theEvent = new LogEventInfo(logLevel, "", message);
theEvent.Properties["OrderId"] =orderId;`

log.Log(theEvent);

... and in your NLog.config file: 
${event-context:item=OrderId}  -- obsolete
${event-properties:item=OrderId} -- renders OrderId
80
Michael Freidgeim

Voici une approche utilisant le GlobalContext.

Configuration:

<target type="Database" name="database" connectionstring="Server=localhost;Database=NLog;Trusted_Connection=True;">
  <commandText>
    INSERT INTO NLogEntries ([Origin], [Message], [LogLevel],[CreatedOn],[OrderId]) VALUES (@Origin,@Message,@LogLevel,@Date, @OrderId);
  </commandText>
  <parameter name="@Date" layout="${date}"/>
  <parameter name="@Origin" layout="${callsite}"/>
  <parameter name="@LogLevel" layout="${level}"/>
  <parameter name="@message" layout="${message}"/>
  <parameter name="@OrderId" layout="${gdc:OrderId}"/> <!-- custom field! -->
</target>

Site d'appel:

var logger = LogManager.GetCurrentClassLogger();
GlobalDiagnosticsContext.Set("OrderId",123);
logger.Debug("What is going on here"); //If you use the logging configuration above, 123 will be logged to the OrderId column in your database

Avec un peu plus d'efforts, vous pouvez envelopper l'enregistreur NLog en utilisant l'une des techniques illustrées ici .

Ou, vous pouvez créer votre propre objet "contextuel" et écrire un LayoutRenderer personnalisé pour en extraire les valeurs et les écrire dans le journal. Les LayourRenderers personnalisés sont faciles à écrire. Vous pouvez voir un exemple dans ma première réponse à cette question . Là, je montre comment écrire votre propre LayoutRenderer qui ajoute la valeur actuelle de System.Diagnostics.Trace.CorrelationManager.ActivityId au message de journal.

36
wageoghe

Si c'est tout ce dont on a besoin, à partir de la version 4.3.3 de NLog, il existe un moyen plus simple de déclarer et d'accéder à des variables personnalisées. Attention: aucune de ces solutions n'est thread-safe.

Ajoutez ce qui suit au NLog.config

<nlog ...
    <!-- optional, add some variables -->  
    ...
    <variable name="myvarone" value="myvalue"/>
    <variable name="myvartwo" value=2/>
     ...
</nlog>

Les variables peuvent être modifiées/accessibles dans le code par:

LogManager.Configuration.Variables["myvarone"] = "New Value"
LogManager.Configuration.Variables["myvartwo"] = 2

Les valeurs peuvent être référencées dans NLog.config:

"${var:myvarone}"  -- renders "New Value"
"${var:myvartwo}"  -- renders 2

Comme je l'ai mentionné ci-dessus var et les objets LogEventInfo sont globaux. Donc, si plusieurs instances sont définies, la modification d'une valeur modifierait la valeur de toutes les instances. Je suis très intéressé si quelqu'un connaît un moyen de déclarer des variables personnalisées par instance pour NLog.

9
Balash

Vous pouvez utiliser le code MDC:

var logger = LogManager.GetCurrentClassLogger();

MDC.Set("OrderId", 123);
MDC.Set("user", HttpContext.Current.User.Identity.Name);
// ... and so on

vérifiez également cela http://weblogs.asp.net/drnetjes/archive/2005/02/16/374780.aspx

2
Eldar

Avec NLog 4.6.3, c'est maintenant plus facile et sûr pour les threads!

Appel

int orderId = 123; 
logger.WithProperty("MyOrderId", orderId).Info("This is my message!"); 

Config:

<target type="Database" name="database" connectionstring="Server=localhost;Database=NLog;Trusted_Connection=True;">
  <commandText>
    INSERT INTO NLogEntries ([Origin], [Message], [LogLevel],[CreatedOn],[OrderId]) VALUES (@Origin,@Message,@LogLevel,@Date, @OrderId);
  </commandText>
  <parameter name="@Date" layout="${date}" dbType="DbType.Date"/>
  <parameter name="@Origin" layout="${callsite}"/>
  <parameter name="@LogLevel" layout="${level}"/>
  <parameter name="@message" layout="${message}"/>
  <parameter name="@OrderId" layout="${event-properties:MyOrderId}" dbType="DbType.Int32"/> <!-- custom field! Note also the DB Type -->
</target>

Remarque, NLog 4.6 prend également en charge DbType - Voir https://nlog-project.org/2019/03/20/nlog-4-6-is-live.html

2
Julian