Как применить разные макеты к одной и той же цели в NLog? - PullRequest
6 голосов
/ 02 марта 2011

NLog позволяет мне использовать SplitGroup, чтобы регистрировать мои сообщения для нескольких целей.Я хотел бы использовать эту функцию, чтобы записывать каждое сообщение в общие, специфичные для пользователя и журналы для конкретной даты сразу:

<variable name="commonLog" value="${logDir}\Common.log" />
<variable name="username" value="${identity:fSNormalize=true:authType=false:isAuthenticated=false}" />
<variable name="userLog" value="${logDir}\ByUser\${username}.log" />
<variable name="dateLog" value="${logDir}\ByDate\${shortdate}.log" />

<target name="logFiles" xsi:type="SplitGroup">
  <target xsi:type="File" fileName="${commonLog}" layout="${myLayout}" />
  <target xsi:type="File" fileName="${userLog}" layout="${myLayout}" />
  <target xsi:type="File" fileName="${dateLog}" layout="${myLayout}" />
</target>

Это здорово, но Я также хочу использовать разные макеты для разных уровней серьезности .Например, errorLayout будет включать информацию об исключении и вставлять маркер [!], чтобы впоследствии я мог выделить ошибки в средствах просмотра журналов, таких как BareTail :

<variable name="stamp" value="${date} ${username} ${logger}" />

<variable name="debugLayout" value="${stamp} ... ${message}" />
<variable name="infoLayout" value="${stamp} [i] ${message}" /> 
<variable name="warnLayout" value="${stamp} [!] ${message}" />
<variable name="errorLayout"
   value="${warnLayout}${newline}${pad:padding=10:inner=${exception:format=ToString}}" />

<!-- logFiles target -->

<rules>
  <logger name="*" level="Debug" writeTo="logFiles" layout="debugLayout"  />
  <logger name="*" level="Info" writeTo="logFiles" layout="infoLayout" />
  <logger name="*" level="Warn" writeTo="logFiles" layout="warnLayout" />
  <logger name="*" level="Error" writeTo="logFiles" layout="errorLayout" />
</rules>

Этот код предполагает Error sвсегда приходят с исключениями, а Warning s нет, но это не главное.

Проблема в , эта конфигурация неверна .Это не будет работать, потому что logger не имеет атрибута layout.Он определен только для target.

Используемый макет должен быть объявлен самими целями, но я не вижу возможности указать разные макеты для разных уровней серьезности.

На данный момент мне пришлось копировать и вставлять один и тот же код конфигурации четыре раза, чтобы иметь четыре разных layout s для одного и того же набора файлов:

<targets>
  <target name="logFilesDebug" xsi:type="SplitGroup">
    <target xsi:type="File" fileName="${commonLog}" layout="${debugLayout}" />
    <target xsi:type="File" fileName="${userLog}" layout="${debugLayout}" />
    <target xsi:type="File" fileName="${dateLog}" layout="${debugLayout}" />
  </target>

  <target name="logFilesInfo" xsi:type="SplitGroup">
    <target xsi:type="File" fileName="${commonLog}" layout="${infoLayout}" />
    <target xsi:type="File" fileName="${userLog}" layout="${infoLayout}" />
    <target xsi:type="File" fileName="${dateLog}" layout="${infoLayout}" />
  </target>

  <target name="logFilesWarn" xsi:type="SplitGroup">
    <target xsi:type="File" fileName="${commonLog}" layout="${warnLayout}" />
    <target xsi:type="File" fileName="${userLog}" layout="${warnLayout}" />
    <target xsi:type="File" fileName="${dateLog}" layout="${warnLayout}" />
  </target>

  <target name="logFilesError" xsi:type="SplitGroup">
    <target xsi:type="File" fileName="${commonLog}" layout="${errorLayout}" />
    <target xsi:type="File" fileName="${userLog}" layout="${errorLayout}" />
    <target xsi:type="File" fileName="${dateLog}" layout="${errorLayout}" />
  </target>
</targets>

<rules>
  <logger name="*" level="Debug" writeTo="logFilesDebug"  />
  <logger name="*" level="Info" writeTo="logFilesInfo" />
  <logger name="*" level="Warn" writeTo="logFilesWarn" />
  <logger name="*" level="Error" writeTo="logFilesError" />
</rules>

Это просто ранит мне глаза.
Есть ли лучший способ сделать это и избежать дублирования?

Ответы [ 2 ]

11 голосов
/ 23 ноября 2012

Альтернативным решением является использование условия when в макете.

target.Layout = "${longdate}|[${level}]|${logger}|${message}${onexception:inner=|${exception}${when:when=(level > LogLevel.Warn):inner=|[!] ${exception:format=ToString:innerFormat=Message:maxInnerExceptionLevel=5} }}"

Я хотел просто предоставить сообщение об исключении, когда что-либо меньше, чем ошибка. Когда произошла ошибка, мне потребовалась полная трассировка стека.

1 голос
/ 03 марта 2011

Я не уверен, но я думаю, что вы, вероятно, застряли с дублированием.Вы хотите, чтобы 4 разных макета были использованы для одного и того же файла, и вы хотите 3 разных файла.Для одной цели требуется один макет.Итак, если вы хотите войти только в 1 файл, вам все равно придется определить 4 цели, каждая из которых указывает на один и тот же файл и у каждого свой макет.Я не думаю, что в NLog есть более удобный способ связать несколько макетов с целью, а затем выбрать один макет на основе содержимого сообщения регистрации.

В зависимости от того, чего именно вы хотите достичь с помощью своих форматов.Вы можете уменьшить дублирование, написав собственный LayoutRenderer.В вашем примере вы показываете, что в макете Debug есть «...», в Info - [i], в Warn - [!], А в Error - исключение Warn +.Вы можете написать LayoutRenderer, который добавляет специальный маркер, в зависимости от уровня сообщения.Таким образом, вы бы свернули Debug, Info и Warn все в один Layout, а Error сохранил бы свой собственный Layout.

Например:

Что-то вроде этого для пользовательского LayoutRenderer (основанного на NLogОбновление 1.0, а не 2.0):

  [LayoutRenderer("LevelMarkerLayoutRenderer")]   
  class LevelMarkerLayoutRenderer : LayoutRenderer   
  {     
    int estimatedSize = 3;      
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {       
      string marker;
      switch (logEvent.Level)
      {
        case Debug:
          marker = "...";
          break;
        case Info:
          marker = "[i]";
          break;
        case Warn:
          marker = "[!]";
          break;
        case Error:
          marker = "[!]";
          break;
        case Fatal:
          marker = "[!]";
          break;
        default:
          marker = "?";
      }

      builder.Append(marker);     
    }      

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)     
    {       
      return estimatedSize;     
    }
  } 

Теперь вы можете настроить два макета: «нормальный» и «ошибка».

Что-то вроде:

<variable name="stamp" value="${date} ${username} ${logger}" />

<variable name="normal" value="${stamp} ${LevelMarkerLayoutRenderer} ${message}" />
<variable name="error"
   value="${warnLayout}${newline}${pad:padding=10:inner=${exception:format=ToString}}" />

Вы могли бы даже создать собственный LayoutRenderer для обработки исключений.Если не исключение, ничего не выводите.Если исключение, объедините новую строку, отступы и строку исключения.

Если у вас был «условный» рендерер макета исключений, то у вас может быть только один макет, который может выглядеть следующим образом:

<variable name="normal" value="${stamp} ${LevelMarkerLayoutRenderer} ${message} ${ConditionalExceptionLayoutRenderer}" />

В большинстве случаев ConditionalExceptionLayoutRenderer будет выдавать значение NULL, поскольку исключений не будет.

Надеюсь, это поможет.

...