简体   繁体   中英

nlog custom target not logging after .net core 2.0

after lifting up our project to .NET Standard 2.0 we have an issue with Nlog. It seems that the custom targes Write() -method does not trigger.

Anyone of you has the same issue or an idea of how to solve the problem?

register custom target:

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;

custom-target:

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>

And this is how we do the log-call:

var theEvent = new LogEventInfo(nLogLevel, logFilterName, message);
theEvent.Properties["SchemaName"] = _schemaTarget;
// more properties added...
var logger = LogManager.GetLogger("DatabaseLog");
logger.Log(theEvent)

With the Framework 4.5 this code worked as we need it. Now it looks like, that the logger.Log(theEvent) just write directly to the database skipping our custom method.

First you register your custom target as type="DatabaseLog" :

ConfigurationItemFactory.Default.Targets.RegisterDefinition("DatabaseLog", typeof(MultiTenantDataBaseLogTarget));

But then you configure the standard target type="Database" :

<target name="DatabaseLog" xsi:type="Database">

But instead of using the a custom target, then I suggest you just change the <commandText> to this:

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

Notice that I have just inserted ${event-properties:item=SchemaName} , so NLog will automatically render the CommandText so you can completely remove MultiTenantDataBaseLogTarget (Improves performance and also allows you to use the NLog AsyncWrapper).

Notice if you want a default SchemaName then you can consider using ${whenEmpty} . See also: https://github.com/NLog/NLog/wiki/WhenEmpty-Layout-Renderer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM