如何将NLog中的自定义字段记录到数据库中?

Kje*_*sen 43 c# nlog

我目前在许多项目中使用NLog.在某些情况下,我登录到数据库.

这是我想做的事情:

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!
)
Run Code Online (Sandbox Code Playgroud)

NLog.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}"/>
  <parameter name="@Origin" layout="${callsite}"/>
  <parameter name="@LogLevel" layout="${level}"/>
  <parameter name="@message" layout="${message}"/>
  <parameter name="@OrderId" layout="${orderId}"/> <!-- custom field! -->
</target>
Run Code Online (Sandbox Code Playgroud)

然后记录这样的事情:

var logger = LogManager.GetCurrentClassLogger();
var orderId = 123;
logger.Debug("What is going on here", orderId);
Run Code Online (Sandbox Code Playgroud)

有没有一个很好的方法来做这个并继续使用NLog?或者,当这些是要求时,我是否必须滚动我自己的记录器并跳过NLog?

MiF*_*vil 82

而不是使用GDC(用于全局静态数据并且在并发日志记录上失败),最好使用  EventProperties-Layout-Renderer  ,它允许传递特定于事件的自定义属性

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
Run Code Online (Sandbox Code Playgroud)

  • 现在不推荐使用`$ {event-context}`,你应该使用[`$ {event-properties}`](https://github.com/nlog/NLog/wiki/EventProperties-Layout-Renderer). (7认同)
  • 根据https://github.com/nlog/nlog/wiki/Layout-Renderers提供的MDC和NDC与log4net的兼容性. (5认同)
  • 您能否添加一个说明GDC和MDC现已过时的来源?我首先尝试了你的解决方案,但转移到标记答案的解决方案,因为它更清洁 - 我不必定义新变量并手动设置日志级别和记录器名称.关于他们的'弃用',我唯一能找到的是他们的名字已经从GDC/MDC变为标记答案所使用的名称(GlobalDiagnosticsContext) - http://nlog-project.org/2009/10/19/nlog-2-向后兼容性和破变化,policy.html (4认同)
  • 使用自定义LogEventInfo实例,您还必须手动设置Timestamp/LoggerName,这不如使用GDC方便. (2认同)

wag*_*ghe 35

以下是使用GlobalContext的一种方法.

组态:

<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>
Run Code Online (Sandbox Code Playgroud)

通话网站:

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
Run Code Online (Sandbox Code Playgroud)

只需稍加努力,您就可以使用此处所示的技术之一包装NLog记录器.

或者,您可以创建自己的"上下文"对象并编写自定义LayoutRenderer以从中提取值并将其写入日志.自定义LayourRenderers易于编写.你可以在我对这个问题的第一个答案中看到一个例子.在那里,我展示了如何编写自己的LayoutRenderer,它将System.Diagnostics.Trace.CorrelationManager.ActivityId的当前值附加到日志消息中.

  • 它不会导致并发写入问题吗? - 我的意思是一个线程设置该值,另一个线程覆盖将由第一个线程写入的值 (7认同)

Bal*_*ash 8

如果这是所有需要的,从NLog版本4.3.3开始,有一种更简单的方式来声明和访问自定义变量. 注意: 这些解决方案都不是线程安全的.

将以下内容添加到NLog.config中

<nlog ...
    <!-- optional, add some variables -->  
    ...
    <variable name="myvarone" value="myvalue"/>
    <variable name="myvartwo" value=2/>
     ...
</nlog>
Run Code Online (Sandbox Code Playgroud)

可以通过以下代码更改/访问变量:

LogManager.Configuration.Variables["myvarone"] = "New Value"
LogManager.Configuration.Variables["myvartwo"] = 2
Run Code Online (Sandbox Code Playgroud)

可以在NLog.config中引用这些值:

"${var:myvarone}"  -- renders "New Value"
"${var:myvartwo}"  -- renders 2
Run Code Online (Sandbox Code Playgroud)

正如我上面提到的,varLogEventInfo对象是全局的.因此,如果定义了多个实例,则更改值将更改所有实例的值.如果有人知道为NLog声明每个实例自定义变量的方法,我会很感兴趣.

  • 迈克尔上面的回答是线程安全的.它没有使用Global LogEventInfo,他正在创建一个新实例. (2认同)

Jul*_*ian 5

使用NLog 4.6.3,这现在变得更容易且线程安全!

呼叫

int orderId = 123; 
logger.WithProperty("MyOrderId", orderId).Info("This is my message!"); 
Run Code Online (Sandbox Code Playgroud)

配置:

<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>
Run Code Online (Sandbox Code Playgroud)

注意,NLog 4.6还支持DbType-请参阅https://nlog-project.org/2019/03/20/nlog-4-6-is-live.html

  • 我认为这是较新版本的NLog的最佳解决方案。+1。 (2认同)