nlog 自定义目标在 .net core 2.0 之后不记录
nlog custom target not logging after .net core 2.0
将我们的项目升级到 .NET Standard 2.0 后,我们遇到了 Nlog 问题。
似乎自定义目标Write()
-方法没有触发。
你们中有人遇到同样的问题或者知道如何解决这个问题吗?
注册自定义目标:
GlobalDiagnosticsContext.Set("configDir", Directory.GetCurrentDirectory());
ConfigurationItemFactory.Default.Targets.RegisterDefinition("DatabaseLog", typeof(MultiTenantDataBaseLogTarget));
var connectionString = Common.Lib.AppSettingsReader.GetConnectionString("DefaultConnection");
if (string.IsNullOrEmpty(connectionString)) // to support the .NET Framework Service DataProvider connectionString = ConfigurationManager.ConnectionStrings["localRuleContext"].ConnectionString;
LogManager.Configuration.Variables["connectionString"] = connectionString;
自定义目标:
using NLog;
using NLog.Common;
using NLog.Targets;
namespace OurNamespace.Logging
{
[Target("DatabaseLog")]
public class MultiTenantDataBaseLogTarget : DatabaseTarget
{
protected override void Write(AsyncLogEventInfo logEvent)
{
CommandText = $@"
insert into {logEvent.LogEvent.Properties["SchemaName"]}.ProtocolLogs (
Timestamp, LogLevel, MessageKey, Message, Parameters, [User], ApplicationName, Action, ObjectId, ObjectName
) values (
@Timestamp, @LogLevel, @MessageKey, @Message, @Parameters, @User, @ApplicationName, @Action, @ObjectId, @ObjectName
);";
base.Write(logEvent);
}
protected override void Write(LogEventInfo logEvent)
{
CommandText = $@"
insert into {logEvent.Properties["SchemaName"]}.ProtocolLogs (
Timestamp, LogLevel, MessageKey, Message, Parameters, [User], ApplicationName, Action, ObjectId, ObjectName
) values (
@Timestamp, @LogLevel, @MessageKey, @Message, @Parameters, @User, @ApplicationName, @Action, @ObjectId, @ObjectName
);";
base.Write(logEvent);
}
}
}
nlog.config
<?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"
throwExceptions="true"
autoReload="true"
internalLogLevel="Trace"
internalLogFile=".\Logs\internal-nlog.txt">
<extensions>
<add assembly="NLog.Targets.ElasticSearch"/>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<target name="DatabaseLog" xsi:type="Database" >
<connectionString>${var:connectionstring}</connectionString>
<commandText>
insert into Schema.ProtocolLogs (
Timestamp, [LogLevel], MessageKey, Message, Parameters, [User], ApplicationName, Action, ObjectId
) values (
@Timestamp, @LogLevel, @MessageKey, @Message, @Parameters, @User, @ApplicationName, @Action, @ObjectId);
</commandText>
<parameter name="@Timestamp" layout="${event-properties:Timestamp:format=yyyy-MM-dd HH\:mm\:ss.fff}" />
<parameter name="@LogLevel" layout="${event-properties:LogLevel}" />
<parameter name="@MessageKey" layout="${event-properties:MessageKey}" />
<parameter name="@Message" layout="${message}" />
<parameter name="@Parameters" layout="${event-properties:Parameters}" />
<parameter name="@User" layout="${event-properties:User}" />
<parameter name="@ApplicationName" layout="${event-properties:ApplicationName}" />
<parameter name="@Action" layout="${event-properties:Action}" />
<parameter name="@ObjectId" layout="${event-properties:ObjectId}" />
<parameter name="@ObjectName" layout="${event-properties:ObjectName}" />
</target>
</targets>
<rules>
<logger name="DatabaseLog" minlevel="Trace" writeTo="DatabaseLog" />
</rules>
</nlog>
这就是我们进行日志调用的方式:
var theEvent = new LogEventInfo(nLogLevel, logFilterName, message);
theEvent.Properties["SchemaName"] = _schemaTarget;
// more properties added...
var logger = LogManager.GetLogger("DatabaseLog");
logger.Log(theEvent)
在 Framework 4.5 中,这段代码可以按我们的需要工作。
现在看来,logger.Log(theEvent)
跳过我们的自定义方法直接写入数据库。
首先,您将自定义目标注册为 type="DatabaseLog"
:
ConfigurationItemFactory.Default.Targets.RegisterDefinition("DatabaseLog", typeof(MultiTenantDataBaseLogTarget));
但是你配置标准目标type="Database"
:
<target name="DatabaseLog" xsi:type="Database">
但是我建议您不要使用自定义目标,而是将 <commandText>
更改为:
<target name="DatabaseLog" xsi:type="Database">
<connectionString>${var:connectionstring}</connectionString>
<commandText>
insert into ${event-properties:item=SchemaName}.ProtocolLogs (
Timestamp, [LogLevel], MessageKey, Message, Parameters, [User], ApplicationName, Action, ObjectId
) values (
@Timestamp, @LogLevel, @MessageKey, @Message, @Parameters, @User, @ApplicationName, @Action, @ObjectId);
</commandText>
</target>
请注意,我刚刚插入了 ${event-properties:item=SchemaName}
,因此 NLog 将自动呈现 CommandText,因此您可以完全删除 MultiTenantDataBaseLogTarget
(提高性能并允许您使用 NLog AsyncWrapper)。
请注意,如果您需要默认的 SchemaName,则可以考虑使用 ${whenEmpty}
。另见:https://github.com/NLog/NLog/wiki/WhenEmpty-Layout-Renderer
将我们的项目升级到 .NET Standard 2.0 后,我们遇到了 Nlog 问题。
似乎自定义目标Write()
-方法没有触发。
你们中有人遇到同样的问题或者知道如何解决这个问题吗?
注册自定义目标:
GlobalDiagnosticsContext.Set("configDir", Directory.GetCurrentDirectory());
ConfigurationItemFactory.Default.Targets.RegisterDefinition("DatabaseLog", typeof(MultiTenantDataBaseLogTarget));
var connectionString = Common.Lib.AppSettingsReader.GetConnectionString("DefaultConnection");
if (string.IsNullOrEmpty(connectionString)) // to support the .NET Framework Service DataProvider connectionString = ConfigurationManager.ConnectionStrings["localRuleContext"].ConnectionString;
LogManager.Configuration.Variables["connectionString"] = connectionString;
自定义目标:
using NLog;
using NLog.Common;
using NLog.Targets;
namespace OurNamespace.Logging
{
[Target("DatabaseLog")]
public class MultiTenantDataBaseLogTarget : DatabaseTarget
{
protected override void Write(AsyncLogEventInfo logEvent)
{
CommandText = $@"
insert into {logEvent.LogEvent.Properties["SchemaName"]}.ProtocolLogs (
Timestamp, LogLevel, MessageKey, Message, Parameters, [User], ApplicationName, Action, ObjectId, ObjectName
) values (
@Timestamp, @LogLevel, @MessageKey, @Message, @Parameters, @User, @ApplicationName, @Action, @ObjectId, @ObjectName
);";
base.Write(logEvent);
}
protected override void Write(LogEventInfo logEvent)
{
CommandText = $@"
insert into {logEvent.Properties["SchemaName"]}.ProtocolLogs (
Timestamp, LogLevel, MessageKey, Message, Parameters, [User], ApplicationName, Action, ObjectId, ObjectName
) values (
@Timestamp, @LogLevel, @MessageKey, @Message, @Parameters, @User, @ApplicationName, @Action, @ObjectId, @ObjectName
);";
base.Write(logEvent);
}
}
}
nlog.config
<?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"
throwExceptions="true"
autoReload="true"
internalLogLevel="Trace"
internalLogFile=".\Logs\internal-nlog.txt">
<extensions>
<add assembly="NLog.Targets.ElasticSearch"/>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<target name="DatabaseLog" xsi:type="Database" >
<connectionString>${var:connectionstring}</connectionString>
<commandText>
insert into Schema.ProtocolLogs (
Timestamp, [LogLevel], MessageKey, Message, Parameters, [User], ApplicationName, Action, ObjectId
) values (
@Timestamp, @LogLevel, @MessageKey, @Message, @Parameters, @User, @ApplicationName, @Action, @ObjectId);
</commandText>
<parameter name="@Timestamp" layout="${event-properties:Timestamp:format=yyyy-MM-dd HH\:mm\:ss.fff}" />
<parameter name="@LogLevel" layout="${event-properties:LogLevel}" />
<parameter name="@MessageKey" layout="${event-properties:MessageKey}" />
<parameter name="@Message" layout="${message}" />
<parameter name="@Parameters" layout="${event-properties:Parameters}" />
<parameter name="@User" layout="${event-properties:User}" />
<parameter name="@ApplicationName" layout="${event-properties:ApplicationName}" />
<parameter name="@Action" layout="${event-properties:Action}" />
<parameter name="@ObjectId" layout="${event-properties:ObjectId}" />
<parameter name="@ObjectName" layout="${event-properties:ObjectName}" />
</target>
</targets>
<rules>
<logger name="DatabaseLog" minlevel="Trace" writeTo="DatabaseLog" />
</rules>
</nlog>
这就是我们进行日志调用的方式:
var theEvent = new LogEventInfo(nLogLevel, logFilterName, message);
theEvent.Properties["SchemaName"] = _schemaTarget;
// more properties added...
var logger = LogManager.GetLogger("DatabaseLog");
logger.Log(theEvent)
在 Framework 4.5 中,这段代码可以按我们的需要工作。
现在看来,logger.Log(theEvent)
跳过我们的自定义方法直接写入数据库。
首先,您将自定义目标注册为 type="DatabaseLog"
:
ConfigurationItemFactory.Default.Targets.RegisterDefinition("DatabaseLog", typeof(MultiTenantDataBaseLogTarget));
但是你配置标准目标type="Database"
:
<target name="DatabaseLog" xsi:type="Database">
但是我建议您不要使用自定义目标,而是将 <commandText>
更改为:
<target name="DatabaseLog" xsi:type="Database">
<connectionString>${var:connectionstring}</connectionString>
<commandText>
insert into ${event-properties:item=SchemaName}.ProtocolLogs (
Timestamp, [LogLevel], MessageKey, Message, Parameters, [User], ApplicationName, Action, ObjectId
) values (
@Timestamp, @LogLevel, @MessageKey, @Message, @Parameters, @User, @ApplicationName, @Action, @ObjectId);
</commandText>
</target>
请注意,我刚刚插入了 ${event-properties:item=SchemaName}
,因此 NLog 将自动呈现 CommandText,因此您可以完全删除 MultiTenantDataBaseLogTarget
(提高性能并允许您使用 NLog AsyncWrapper)。
请注意,如果您需要默认的 SchemaName,则可以考虑使用 ${whenEmpty}
。另见:https://github.com/NLog/NLog/wiki/WhenEmpty-Layout-Renderer