Подтвердить что ты не робот

Как зарегистрировать настраиваемое поле в NLog для базы данных?

В настоящее время я использую 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, когда это необходимо?

4b9b3361

Ответ 1

Вместо использования 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

Ответ 2

Вот один подход, использующий 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 к сообщению журнала.

Ответ 3

Если это все нужно, с версии 4.3.3 NLog существует более простой способ объявления и доступа к пользовательским переменным. Остерегайтесь: ни одно из этих решений не является потокобезопасным.

Добавьте в файл 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

Как я уже упоминал выше, объекты var и LogEventInfo являются глобальными. Поэтому, если определено несколько экземпляров, изменение значения изменит значение для всех экземпляров. Мне очень интересно, знает ли кто-нибудь способ объявить пользовательские переменные для экземпляра для NLog.

Ответ 4

Вы можете использовать код 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

Ответ 5

С NLog 4.6.3 это стало проще и надежнее!

Вызов

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

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}" 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.