在将我们的项目提升到.NET Standard 2.0之后,我们遇到了Nlog的问题。似乎自定义targes Write()
-method不会触发。
你们中的任何人都有同样的问题或想法如何解决问题?
注册自定义目标:
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