53

我目前在很多项目中使用 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!
)

和带有这个目标的 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>

然后记录如下内容:

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

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

4

5 回答 5

88

2022 年 2 月 11 日更新:较新版本的 NLOG 有其他解决方案 - 请参阅Julian 的回答

与其使用用于全局静态数据并在并发日志记录上失败的 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
于 2013-07-20T23:40:31.720 回答
37

这是使用 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>

调用站点:

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

稍加努力,您就可以使用此处说明的一种技术来包装 NLog 记录器。

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

于 2012-09-14T15:23:36.473 回答
14

NLog 4.5 引入了结构化日志,所以你可以这样做:

logger.Debug("What is going on here. OrderId={MyOrderId}", orderId);

使用 NLog 4.6.3 可以创建临时 Logger,它具有所需的属性,使用WithProperty

称呼

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

配置:

<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>

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

于 2019-06-22T23:16:42.370 回答
8

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

将以下内容添加到 NLog.config

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

可以通过以下方式在代码中更改/访问变量:

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

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

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

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

于 2016-05-05T00:59:01.063 回答
2

您可以使用 MDC 代码:

var logger = LogManager.GetCurrentClassLogger();

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

还要检查这个http://weblogs.asp.net/drnetjes/archive/2005/02/16/374780.aspx

于 2012-09-23T14:42:20.620 回答