Пользовательская цель nlog не регистрируется после .net core 2.0 - PullRequest
1 голос
/ 11 апреля 2019

после поднятия нашего проекта до .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) просто напишите непосредственно в базу данных, пропустив наш пользовательский метод.

1 Ответ

1 голос
/ 11 апреля 2019

Сначала вы зарегистрируете свою пользовательскую цель как 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).

Обратите внимание, что если вы хотите использовать имя схемы по умолчанию, вы можете использовать ${whenEmpty}. Смотри также: https://github.com/NLog/NLog/wiki/WhenEmpty-Layout-Renderer

...