가장 유용한 NLog 구성 [닫기]


348

NLog로 로깅하는 데 가장 적합하거나 유용한 구성은 무엇입니까? (유용한 한 간단하거나 복잡 할 수 있습니다.)

특정 크기의 로그 파일을 자동으로 롤오버하거나 예외가 있는지 여부에 따라 레이아웃 (로그 메시지)을 변경하거나 오류가 발생하면 로그 수준을 올리는 등의 예제를 생각하고 있습니다.

다음은 몇 가지 링크입니다.


3
다음은 테스트를 기반으로 한 성능 조정 팁입니다. deep-depth.blogspot.com/2014/01/…
Neil

답변:


391

이 중 일부는 구성 제안을 엄격하게 제시하기보다는 일반적인 NLog (또는 로깅) 팁 범주에 속합니다.

여기 SO의 일반적인 로깅 링크가 있습니다 (이들 중 일부 또는 전부를 이미 보았을 것입니다).

log4net 대 Nlog

모범 사례 로깅

벌목 정면의 요점은 무엇입니까?

로거는 왜 수업마다 로거를 사용하도록 권장합니까?

클래스를 기반으로 로거의 이름을 지정하는 일반적인 패턴을 사용하십시오 Logger logger = LogManager.GetCurrentClassLogger(). 이를 통해 로거의 세부 수준을 높일 수 있으며 로거 구성 (전역, 네임 스페이스, 특정 로거 이름 등으로 제어)을 유연하게 구성 할 수 있습니다.

적절한 경우 클래스 이름이 아닌 로거를 사용하십시오. 실제로 로깅을 개별적으로 제어하려는 기능이 하나있을 수 있습니다. 교차 절단 로깅 문제 (성능 로깅)가있을 수 있습니다.

클래스 이름 기반 로깅을 사용하지 않는 경우 구성의 유연성을 유지할 수 있도록 로거의 이름을 일종의 계층 구조 (기능 영역에 따라 다름)로 지정하는 것이 좋습니다. 예를 들어 "데이터베이스"기능 영역, "분석"FA 및 "ui"FA가있을 수 있습니다. 이들 각각에는 하위 영역이있을 수 있습니다. 따라서 다음과 같이 로거를 요청할 수 있습니다.

Logger logger = LogManager.GetLogger("Database.Connect");
Logger logger = LogManager.GetLogger("Database.Query");
Logger logger = LogManager.GetLogger("Database.SQL");
Logger logger = LogManager.GetLogger("Analysis.Financial");
Logger logger = LogManager.GetLogger("Analysis.Personnel");
Logger logger = LogManager.GetLogger("Analysis.Inventory");

등등. 계층 적 로거를 사용하면 전역 ( "*"또는 루트 로거), FA (데이터베이스, 분석, UI) 또는 하위 영역 (Database.Connect 등)별로 로깅을 구성 할 수 있습니다.

로거에는 많은 구성 옵션이 있습니다.

<logger name="Name.Space.Class1" minlevel="Debug" writeTo="f1" /> 
<logger name="Name.Space.Class1" levels="Debug,Error" writeTo="f1" /> 
<logger name="Name.Space.*" writeTo="f3,f4" />
<logger name="Name.Space.*" minlevel="Debug" maxlevel="Error" final="true" /> 

각 옵션의 의미에 대한 자세한 내용은 NLog 도움말 을 참조하십시오 . 아마도 가장 주목할만한 항목은 로거 규칙 와일드 카드 기능, 단일 로거 명령문에 대해 여러 로거 규칙이 "실행"될 수 있으며 로거 규칙이 "최종"으로 표시 될 수 있다는 개념 일 것입니다. 주어진 로깅 문.

GlobalDiagnosticContext, MappedDiagnosticContext 및 NestedDiagnosticContext를 사용하여 출력에 추가 컨텍스트를 추가하십시오.

구성 파일에서 "variable"을 사용하여 단순화하십시오. 예를 들어, 레이아웃에 변수를 정의한 다음 레이아웃을 직접 지정하지 않고 대상 구성에서 변수를 참조 할 수 있습니다.

  <variable name="brief" value="${longdate} | ${level} | ${logger} | ${message}"/>
  <variable name="verbose" value="${longdate} | ${machinename} | ${processid} | ${processname} | ${level} | ${logger} | ${message}"/>
  <targets>
    <target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${shortdate}.log" />
    <target name="console" xsi:type="ColoredConsole" layout="${brief}" />
  </targets>

또는 레이아웃에 추가 할 "사용자 지정"속성 집합을 만들 수도 있습니다.

  <variable name="mycontext" value="${gdc:item=appname} , ${mdc:item=threadprop}"/>
  <variable name="fmt1withcontext" value="${longdate} | ${level} | ${logger} | [${mycontext}] |${message}"/>
  <variable name="fmt2withcontext" value="${shortdate} | ${level} | ${logger} | [${mycontext}] |${message}"/>

또는 구성을 통해 "일"또는 "월"레이아웃 렌더러를 작성하는 등의 작업을 수행 할 수 있습니다.

  <variable name="day" value="${date:format=dddd}"/>
  <variable name="month" value="${date:format=MMMM}"/>
  <variable name="fmt" value="${longdate} | ${level} | ${logger} | ${day} | ${month} | ${message}"/>
  <targets>
    <target name="console" xsi:type="ColoredConsole" layout="${fmt}" />
  </targets>

레이아웃 렌더를 사용하여 파일 이름을 정의 할 수도 있습니다.

  <variable name="day" value="${date:format=dddd}"/>
  <targets>
    <target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${day}.log" />
  </targets>

매일 파일을 롤링하면 각 파일의 이름을 "Monday.log", "Tuesday.log"등으로 지정할 수 있습니다.

자신 만의 레이아웃 렌더러를 작성하는 것을 두려워하지 마십시오. 구성을 통해 쉽고 컨텍스트 정보를 로그 파일에 추가 할 수 있습니다. 예를 들어 Trace.CorrelationManager.ActivityId를 로그에 추가 할 수있는 레이아웃 렌더러 (2.0이 아닌 NLog 1.x 기반)는 다음과 같습니다.

  [LayoutRenderer("ActivityId")]
  class ActivityIdLayoutRenderer : LayoutRenderer
  {
    int estimatedSize = Guid.Empty.ToString().Length;

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
      builder.Append(Trace.CorrelationManager.ActivityId);
    }

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

다음과 같이 NLog 확장 (어떤 어셈블리)을 NLog에 알려주십시오.

  <extensions>
    <add assembly="MyNLogExtensions"/>
  </extensions>

다음과 같이 사용자 정의 레이아웃 렌더러를 사용하십시오.

  <variable name="fmt" value="${longdate} | ${ActivityId} | ${message}"/>

비동기 대상을 사용하십시오.

<nlog>
  <targets async="true">
    <!-- all targets in this section will automatically be asynchronous -->
  </targets>
</nlog>

기본 대상 래퍼 :

<nlog>  
  <targets>  
    <default-wrapper xsi:type="BufferingWrapper" bufferSize="100"/>  
    <target name="f1" xsi:type="File" fileName="f1.txt"/>  
    <target name="f2" xsi:type="File" fileName="f2.txt"/>  
  </targets>  
  <targets>  
    <default-wrapper xsi:type="AsyncWrapper">  
      <wrapper xsi:type="RetryingWrapper"/>  
    </default-wrapper>  
    <target name="n1" xsi:type="Network" address="tcp://localhost:4001"/>  
    <target name="n2" xsi:type="Network" address="tcp://localhost:4002"/>  
    <target name="n3" xsi:type="Network" address="tcp://localhost:4003"/>  
  </targets>  
</nlog>

적절한 경우. 이에 대한 자세한 내용은 NLog 문서를 참조하십시오.

구성이 변경되면 NLog에보고 자동으로 다시로드하도록 지시하십시오.

<nlog autoReload="true" /> 

NLog 문제 해결에 도움이되는 몇 가지 구성 옵션이 있습니다

<nlog throwExceptions="true" />
<nlog internalLogFile="file.txt" />
<nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" />
<nlog internalLogToConsole="false|true" />
<nlog internalLogToConsoleError="false|true" />

자세한 내용은 NLog 도움말을 참조하십시오.

NLog 2.0에는 LayoutRenderer 래퍼가 추가되어 레이아웃 렌더러의 출력에서 ​​추가 처리를 수행 할 수 있습니다 (예 : 공백 자르기, 대문자, 소문자 등).

NLog에 대한 엄격한 의존성으로부터 코드를 격리하고 올바르게 감싸려면 로거를 감싸는 것을 두려워하지 마십시오. NLog의 github 저장소에서 랩핑하는 방법에 대한 예제가 있습니다. 랩핑해야하는 또 다른 이유는 로그 된 각 메시지에 특정 컨텍스트 정보를 자동으로 추가 (LogEventInfo.Context에 넣어서)하기 때문일 수 있습니다.

NLog (또는 그 문제에 대한 다른 로깅 프레임 워크)를 래핑 (또는 추상화)하는 장단점이 있습니다. 약간의 노력만으로도 양면을 제시하는 데 대한 많은 정보를 찾을 수 있습니다.

줄 바꿈을 고려중인 경우 Common.Logging 사용을 고려 하십시오 . 그것은 잘 작동하며 원하는 경우 다른 로깅 프레임 워크로 쉽게 전환 할 수 있습니다. 랩핑을 고려중인 경우 컨텍스트 오브젝트 (GDC, MDC, NDC)를 처리하는 방법을 고려하십시오. Common.Logging은 현재 이들에 대한 추상화를 지원하지 않지만 추가 할 수있는 대기열에있을 것입니다.


3
좋은 대답입니다. 한 가지만 추가하면 $ {machine}은 $ {machinename}이어야합니다. github.com/nlog/NLog/wiki/Layout-Renderers를 참조하십시오 .
liang

2
Common.Logging을 분기하고 누락 된 추상화를 추가했습니다 ( GitHub 프로젝트 또는 NuGet 참조) .
Danny Varod

나는 자신의 문서에서 nlog에 대한 유익한 정보를 찾지 못했습니다. 아마도 github 예제를 잘못보고 있습니까? 누가 알아.
JARRRRG

해당 커스텀 렌더러를 API와 함께 사용하는 방법 (구성 파일 없음) 여기입니다 내가 달성하기 위해 노력하고있어.
InteXX

알았어 NewLine레이아웃 작업을 수행합니다. 여기에 내가 생각해 낸 것이 있습니다. 내가 기대했던 것보다 훨씬 간단합니다.
InteXX

65

예외를 다르게 취급

우리는 종종 예외가있을 때 더 많은 정보를 얻고 싶어합니다. 다음 구성에는 예외 정보가 있는지 여부를 필터링하는 두 개의 대상 (파일과 콘솔)이 있습니다. (편집 : Jarek은 vNext 에서이 작업을 수행 하는 새로운 방법에 대해 게시 했습니다 .)

핵심은 래퍼 대상을 갖는 것입니다. xsi:type="FilteringWrapper" condition="length('${exception}')>0"

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.mono2.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Warn"
      internalLogFile="nlog log.log"
      >
    <variable name="VerboseLayout" 
              value="${longdate} ${level:upperCase=true} ${message}  
                    (${callsite:includSourcePath=true})"            />
    <variable name="ExceptionVerboseLayout"  
              value="${VerboseLayout} (${stacktrace:topFrames=10})  
                     ${exception:format=ToString}"                  />

    <targets async="true">
        <target name="file" xsi:type="File" fileName="log.log"
                layout="${VerboseLayout}">
        </target>

        <target name="fileAsException"  
                xsi:type="FilteringWrapper" 
                condition="length('${exception}')>0">
            <target xsi:type="File"  
                    fileName="log.log"  
                    layout="${ExceptionVerboseLayout}" />
        </target>

        <target xsi:type="ColoredConsole"
                name="console"
                layout="${NormalLayout}"/>

        <target xsi:type="FilteringWrapper"  
                condition="length('${exception}')>0"  
                name="consoleException">
            <target xsi:type="ColoredConsole" 
                    layout="${ExceptionVerboseLayout}" />
        </target>
    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="console,consoleException" />
        <logger name="*" minlevel="Warn" writeTo="file,fileAsException" />
    </rules>

</nlog>

1
별도의 대상과 FilteringWrapper를 사용하면 예외 형식을 지정하는 것이 좋습니다. 방금 출력에 {exception} 레이아웃 렌더러를 포함시키고 싶은 사람의 질문에 최근에 답변했지만 예외가 없으면 분명히 기록 된 ()을 원하지 않습니다. 이 기술은 아마도 그에게 잘 작동 할 것입니다.
wageoghe

+1 매우 좋습니다. 나는 이것을 오랫동안 북마크 해왔고 조건부 레이아웃과 관련하여 다른 SO 질문에서 "Pat 's comment"를 언급했다.
eduncan911

1
예외가 기록되면 두 번 기록됩니다 (VerboseLayout 부분).
Tien Do

2
규칙 minlevel = "Warn"을 "file, fileAsException"으로 설정했기 때문에 내일 내 프로젝트에서 시도했지만 모든 로그는 먼저 파일 대상 (필터 없음)으로 기록되고 예외 일 경우 (필터링 됨) condition) 또한 fileAsException과 함께 기록됩니다.
Tien Do

3
@Tiendq 아, 알겠습니다. 예외 자체 (자세한 내용)는 한 번만 기록되지만 메시지는 두 번 기록됩니다. 에 추가 condition="length('${exception}')=0(또는 가능 ==)하여 이를 수정할 수 있습니다 target name="file".
Pat

60

분명히 Windows 용 Growl과 함께 NLog를 사용할 수 있습니다 .

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

    <extensions>
        <add assembly="NLog.Targets.GrowlNotify" />
    </extensions>

    <targets>
        <target name="growl" type="GrowlNotify" password="" host="" port="" />
    </targets>

    <rules>
        <logger name="*" minLevel="Trace" appendTo="growl"/>
    </rules>

</nlog>

Growl for Windows 용 NLog Growl for Windows가있는 NLog 추적 메시지 Windows 용 Growl을 사용한 NLog 디버그 메시지 Growl for Windows와 함께 NLog 정보 메시지 Growl for Windows에서 NLog 경고 메시지 Growl for Windows의 NLog 오류 메시지 Growl for Windows와 함께 NLog 치명적인 메시지


리모트 연결에 대해 어떻게해야합니까? 일이 localhost에 대해 작동하지만 호스트에 일부 IP 주소를 부여하면 작동하지 않습니다!
Neel

@Neel, 대상 컴퓨터의 Growl에서 "보안"설정을 확인해야합니다. "LAN"알림을 명시 적으로 활성화해야하며 암호를 설정해야 할 수 있습니다 (NLog 대상에 추가해야 함). 그러나 나는 "로컬 머신"의 "원본"과 함께 Growl에 원격 알림이 나타나는 것을 좋아하지 않았다. 알림이 시작된 위치를 확인하려면 호스트를 로그 항목에 추가해야합니다.
Kenny Evitt

로컬 컴퓨터에서 알림이 작동하지만 원격으로는 작동하지 않습니다. 보안 설정에는 growl에 암호가 없으므로 IP와 포트만 추가하면됩니다. 그러나 아무것도 보내지지 않습니다.
Jack Reilly

1
이 프로젝트는 100 % 종료되었습니다.
개발자

28

프로그래밍 방식으로 XML을 통해 NLog 구성

뭐? NLog를 구성 파일에서 읽지 않고 앱에서 NLog XML을 NLog로 직접 지정할 수 있다는 것을 알고 있습니까? 당신은 할 수 있습니다. 분산 앱이 있고 어디에서나 동일한 구성을 사용하려고한다고 가정 해 봅시다. 구성 파일을 각 위치에 유지하고 별도로 유지 관리하거나 중앙 위치에 유지 관리하여 위성 위치로 푸시하거나 다른 많은 작업을 수행 할 수 있습니다. 또는 XML을 데이터베이스에 저장하고 앱을 시작할 때 가져와 해당 XML을 사용하여 NLog를 직접 구성 할 수 있습니다 (정기적으로 다시 확인되어 변경되었는지 확인).

  string xml = @"<nlog>
                   <targets>
                     <target name='console' type='Console' layout='${message}' />
                   </targets>

                   <rules>
                     <logger name='*' minlevel='Error' writeTo='console' />
                   </rules>
                 </nlog>";

  StringReader sr = new StringReader(xml);
  XmlReader xr = XmlReader.Create(sr);
  XmlLoggingConfiguration config = new XmlLoggingConfiguration(xr, null);
  LogManager.Configuration = config;
  //NLog is now configured just as if the XML above had been in NLog.config or app.config

  logger.Trace("Hello - Trace"); //Won't log
  logger.Debug("Hello - Debug"); //Won't log
  logger.Info("Hello - Info");   //Won't log
  logger.Warn("Hello - Warn");   //Won't log
  logger.Error("Hello - Error"); //Will log
  logger.Fatal("Hello - Fatal"); //Will log

  //Now let's change the config (the root logging level) ...
  string xml2 = @"<nlog>
                  <targets>
                     <target name='console' type='Console' layout='${message}' />
                   </targets>

                   <rules>
                     <logger name='*' minlevel='Trace' writeTo='console' />
                   </rules>
                 </nlog>";

  StringReader sr2 = new StringReader(xml2);
  XmlReader xr2 = XmlReader.Create(sr2);
  XmlLoggingConfiguration config2 = new XmlLoggingConfiguration(xr2, null);
  LogManager.Configuration = config2;

  logger.Trace("Hello - Trace"); //Will log
  logger.Debug("Hello - Debug"); //Will log
  logger.Info("Hello - Info");   //Will log
  logger.Warn("Hello - Warn");   //Will log
  logger.Error("Hello - Error"); //Will log
  logger.Fatal("Hello - Fatal"); //Will log

이것이 얼마나 강력한 지 잘 모르겠지만이 예제는 이와 같이 구성하려고하는 사람들에게 유용한 시작점을 제공합니다.


이 기능을 사용하지 않으면 로깅 시스템을 동적으로 재구성 할 수 없습니다. 외부 파일 (포함)에 링크하는 경우 특히 그렇습니다
Newtopian

2
이것은 다음을 포함하여 "좋은"XML을 작성해야했지만 다음과 같이 작동했습니다.<?xml version='1.0' encoding='utf-8' ?><nlog xmlns='http://nlog-project.org/schemas/NLog.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
Gady

1
이것은 중앙 집중식 구성에 대한 좋은 방법입니다. 이 샘플에서 하드 코딩 된 XML 인 미래 독자는 데모 전용 (IMHO) 전용이므로 데이터베이스 또는 중앙 집중식 파일에서 파일을 읽는 것이 실제 구현 일 수 있습니다.
granadaCoder

@wageoghe; 오류가 발생하는 이유 (로거가 존재하지 않음)? 방금 코드를 복사하여 붙여 넣기
Bsflasher

22

오류 유무에 따라 다른 레벨 로깅

이 예제를 사용하면 코드에 오류가있을 때 자세한 정보를 얻을 수 있습니다. 기본적으로 메시지를 버퍼링 하고 특정 조건이 충족 되지 않으면 (예 : 오류가 발생하여 로그 수준이> = 오류) 특정 로그 수준 (예 : 경고)의 메시지 만 출력 하면 더 많은 정보를 출력합니다 (예 : 로그 수준의 모든 메시지> = 추적). 메시지가 버퍼링되므로 오류 또는 오류 예외가 기록 되기 전에 발생한 문제에 대한 추적 정보를 수집 할 수 있습니다 . 매우 유용합니다!

나는 소스 코드의 예제에서 이것을 수정했다 . AspNetBufferingWrapper(내 것이 ASP 앱이 아니기 때문에) 생략했기 때문에 처음에 던져졌습니다 .PostFilteringWrapper 에는 버퍼링 된 대상이 필요합니다. 있습니다 target-ref(I는 .NET 4.0 앱 1.0 새로 고침을 사용하고 있습니다) 위의 링크 된 예에서 사용 된 요소가 NLog 1.0에서 사용할 수 없습니다; 래퍼 블록 안에 대상을 넣어야합니다. 또한 논리 구문 (즉,보다 크거나 작은 심볼, <및>)은 해당 심볼 (예 : &gt;&lt;) 의 XML 이스케이프가 아닌 심볼을 사용해야합니다 . 그렇지 않으면 NLog가 오류가 발생합니다.

app.config :

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
    </configSections>

    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          throwExceptions="true" internalLogToConsole="true" internalLogLevel="Warn" internalLogFile="nlog.log">
        <variable name="appTitle" value="My app"/>
        <variable name="csvPath" value="${specialfolder:folder=Desktop:file=${appTitle} log.csv}"/>

        <targets async="true">
            <!--The following will keep the default number of log messages in a buffer and write out certain levels if there is an error and other levels if there is not. Messages that appeared before the error (in code) will be included, since they are buffered.-->
            <wrapper-target xsi:type="BufferingWrapper" name="smartLog">
                <wrapper-target xsi:type="PostFilteringWrapper">
                    <!--<target-ref name="fileAsCsv"/>-->
                    <target xsi:type="File" fileName="${csvPath}"
                    archiveAboveSize="4194304" concurrentWrites="false" maxArchiveFiles="1" archiveNumbering="Sequence"
                    >
                        <layout xsi:type="CsvLayout" delimiter="Tab" withHeader="false">
                            <column name="time" layout="${longdate}" />
                            <column name="level" layout="${level:upperCase=true}"/>
                            <column name="message" layout="${message}" />
                            <column name="callsite" layout="${callsite:includeSourcePath=true}" />
                            <column name="stacktrace" layout="${stacktrace:topFrames=10}" />
                            <column name="exception" layout="${exception:format=ToString}"/>
                            <!--<column name="logger" layout="${logger}"/>-->
                        </layout>
                    </target>

                     <!--during normal execution only log certain messages--> 
                    <defaultFilter>level >= LogLevel.Warn</defaultFilter>

                     <!--if there is at least one error, log everything from trace level--> 
                    <when exists="level >= LogLevel.Error" filter="level >= LogLevel.Trace" />
                </wrapper-target>
            </wrapper-target>

        </targets>

        <rules>
            <logger name="*" minlevel="Trace" writeTo="smartLog"/>
        </rules>
    </nlog>
</configuration>

NLog의 일부 버전 (모노 및 2.0)에서는 StackOverflowException이 발생하지만 다른 버전에서는 발생하지 않습니다 (NLog 1 새로 고침).
Pat

오버플로에 관해서는-레이아웃이 CSV 유형이기 때문입니다. 정기 레이아웃을 수행하면 아무런 문제가 없습니다.
Pat

거기에 대한 fileAsCsv target-ref는 무엇입니까? NLog v2.0.0.2000에 대해이 예제를 사용하려고하지만 지금까지 실패했습니다.
피터 Mounce

@PeterMounce fileAsCsvtarget-ref는 내 테스트의 인공물입니다. NLog 2에 NLog 1 / Refresh에는 없었던 CsvLayouts에 문제가 있거나 있다고 생각합니다.
Pat

22

이 질문에 대해 합리적으로 흥미로운 몇 가지 답변을 제공했습니다.

Nlog-로그 파일의 헤더 섹션 생성

헤더 추가 :

질문은 로그 파일에 헤더를 추가하는 방법을 알고 싶었습니다. 이와 같은 구성 항목을 사용하면 나머지 로그 항목의 형식과 별도로 헤더 형식을 정의 할 수 있습니다. 응용 프로그램을 시작할 때 "headerlogger"라고하는 단일 로거를 사용하여 단일 메시지를 기록하면 헤더가 나타납니다.

헤더 및 파일 레이아웃을 정의하십시오.

  <variable name="HeaderLayout" value="This is the header.  Start time = ${longdate} Machine = ${machinename} Product version = ${gdc:item=version}"/>
  <variable name="FileLayout" value="${longdate} | ${logger} | ${level} | ${message}" />

레이아웃을 사용하여 대상을 정의하십시오.

<target name="fileHeader" xsi:type="File" fileName="xxx.log" layout="${HeaderLayout}" />
<target name="file" xsi:type="File" fileName="xxx.log" layout="${InfoLayout}" />

로거를 정의하십시오.

<rules>
  <logger name="headerlogger" minlevel="Trace" writeTo="fileHeader" final="true" />
  <logger name="*" minlevel="Trace" writeTo="file" />
</rules>

프로그램 초기에 헤더를 작성하십시오.

  GlobalDiagnosticsContext.Set("version", "01.00.00.25");

  LogManager.GetLogger("headerlogger").Info("It doesn't matter what this is because the header format does not include the message, although it could");

이것은 "예외를 다르게 처리"아이디어의 다른 버전 일뿐입니다.

각기 다른 로그 레벨을 다른 레이아웃으로 기록

마찬가지로 포스터는 로깅 수준마다 형식을 변경하는 방법을 알고 싶어했습니다. 최종 목표가 무엇인지 (그리고 "더 나은"방법으로 달성 될 수 있는지) 확실하지 않았지만, 그가 요청한 구성을 제공 할 수있었습니다.

  <variable name="TraceLayout" value="This is a TRACE - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="DebugLayout" value="This is a DEBUG - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="InfoLayout" value="This is an INFO - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="WarnLayout" value="This is a WARN - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="ErrorLayout" value="This is an ERROR - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="FatalLayout" value="This is a FATAL - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <targets> 
    <target name="fileAsTrace" xsi:type="FilteringWrapper" condition="level==LogLevel.Trace"> 
      <target xsi:type="File" fileName="xxx.log" layout="${TraceLayout}" /> 
    </target> 
    <target name="fileAsDebug" xsi:type="FilteringWrapper" condition="level==LogLevel.Debug"> 
      <target xsi:type="File" fileName="xxx.log" layout="${DebugLayout}" /> 
    </target> 
    <target name="fileAsInfo" xsi:type="FilteringWrapper" condition="level==LogLevel.Info"> 
      <target xsi:type="File" fileName="xxx.log" layout="${InfoLayout}" /> 
    </target> 
    <target name="fileAsWarn" xsi:type="FilteringWrapper" condition="level==LogLevel.Warn"> 
      <target xsi:type="File" fileName="xxx.log" layout="${WarnLayout}" /> 
    </target> 
    <target name="fileAsError" xsi:type="FilteringWrapper" condition="level==LogLevel.Error"> 
      <target xsi:type="File" fileName="xxx.log" layout="${ErrorLayout}" /> 
    </target> 
    <target name="fileAsFatal" xsi:type="FilteringWrapper" condition="level==LogLevel.Fatal"> 
      <target xsi:type="File" fileName="xxx.log" layout="${FatalLayout}" /> 
    </target> 
  </targets> 


    <rules> 
      <logger name="*" minlevel="Trace" writeTo="fileAsTrace,fileAsDebug,fileAsInfo,fileAsWarn,fileAsError,fileAsFatal" /> 
      <logger name="*" minlevel="Info" writeTo="dbg" /> 
    </rules> 

다시 예외를 다르게 처리하는 것과 매우 유사합니다 .


1
멋있는! 나는 GlobalDiagnosticsContext전에 본 적이 없었다 .
Pat

10

트위터에 로그인

log4net Twitter Appender에 대한이 게시물을 기반으로, 나는 NLog Twitter Target (2.0이 아닌 NLog 1.0 새로 고침 사용)을 작성하려고 노력할 것이라고 생각했습니다. 아아, 지금까지 실제로 성공적으로 게시 할 트윗을 얻을 수 없었습니다. 내 코드, 트위터, 회사의 인터넷 연결 / 방화벽 또는 무엇에 문제가 있는지 모르겠습니다. 누군가 코드를 시험해 보는 데 관심이있는 경우 여기에 코드를 게시하고 있습니다. 세 가지 다른 "포스트"방법이 있습니다. 내가 시도한 첫 번째는 PostMessageToTwitter입니다. PostMessageToTwitter는 본질적으로 orignal post의 PostLoggingEvent와 동일합니다. 그것을 사용하면 401 예외가 발생합니다. PostMessageBasic은 동일한 예외를받습니다. PostMessage는 오류없이 실행되지만 메시지는 여전히 Twitter에 적용되지 않습니다. PostMessage와 PostMessageBasic은 SO에서 찾은 예제를 기반으로합니다.

참고 로, @Jason Diller 가 트위터에서 "다음 달"기본 인증을 해제 할 것이라는 이 게시물 의 답변에 대한 의견을 찾았 습니다 . 이것은 2010 년 5 월에 다시 시작되었으며 이제 2010 년 12 월이므로 이것이 작동하지 않는 이유 일 수 있습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Web;
using System.IO;

using NLog;
using NLog.Targets;
using NLog.Config;

namespace NLogExtensions
{
  [Target("TwitterTarget")]
  public class TwitterTarget : TargetWithLayout
  {
    private const string REQUEST_CONTENT_TYPE = "application/x-www-form-urlencoded";  

    private const string REQUEST_METHOD = "POST";  

    // The source attribute has been removed from the Twitter API,  
    // unless you're using OAuth.  
    // Even if you are using OAuth, there's still an approval process.  
    // Not worth it; "API" will work for now!  
    // private const string TWITTER_SOURCE_NAME = "Log4Net";  
    private const string TWITTER_UPDATE_URL_FORMAT = "http://twitter.com/statuses/update.xml?status={0}";  

    [RequiredParameter]
    public string TwitterUserName { get; set; }

    [RequiredParameter]
    public string TwitterPassword { get; set; }

    protected override void Write(LogEventInfo logEvent)
    {
      if (string.IsNullOrWhiteSpace(TwitterUserName) || string.IsNullOrWhiteSpace(TwitterPassword)) return;

      string msg = this.CompiledLayout.GetFormattedMessage(logEvent);

      if (string.IsNullOrWhiteSpace(msg)) return;

      try
      {
        //PostMessageToTwitter(msg);
        PostMessageBasic(msg);
      }
      catch (Exception ex)
      {
        //Should probably do something here ...
      }
    }

    private void PostMessageBasic(string msg)
    {
      // Create a webclient with the twitter account credentials, which will be used to set the HTTP header for basic authentication 
      WebClient client = new WebClient { Credentials = new NetworkCredential { UserName = TwitterUserName, Password = TwitterPassword } };

      // Don't wait to receive a 100 Continue HTTP response from the server before sending out the message body 
      ServicePointManager.Expect100Continue = false;

      // Construct the message body 
      byte[] messageBody = Encoding.ASCII.GetBytes("status=" + msg);

      // Send the HTTP headers and message body (a.k.a. Post the data) 
      client.UploadData(@"http://twitter.com/statuses/update.xml", messageBody);
    }

    private void PostMessage(string msg)
    {
      string user = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(TwitterUserName + ":" + TwitterPassword));
      byte [] bytes = System.Text.Encoding.UTF8.GetBytes("status=" + msg.ToTweet());
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://twitter.com/statuses/update.xml");
      request.Method = "POST";
      request.ServicePoint.Expect100Continue = false;
      request.Headers.Add("Authorization", "Basic " + user);
      request.ContentType = "application/x-www-form-urlencoded";
      request.ContentLength = bytes.Length;
      Stream reqStream = request.GetRequestStream();
      reqStream.Write(bytes, 0, bytes.Length);
      reqStream.Close();
    }

    private void PostMessageToTwitter(string msg)
    {
      var updateRequest = HttpWebRequest.Create(string.Format(TWITTER_UPDATE_URL_FORMAT,
                                                HttpUtility.UrlEncode(msg.ToTweet()))) as HttpWebRequest;
      updateRequest.ContentLength = 0;
      updateRequest.ContentType = REQUEST_CONTENT_TYPE;
      updateRequest.Credentials = new NetworkCredential(TwitterUserName, TwitterPassword);
      updateRequest.Method = REQUEST_METHOD;

      updateRequest.ServicePoint.Expect100Continue = false;

      var updateResponse = updateRequest.GetResponse() as HttpWebResponse;

      if (updateResponse.StatusCode != HttpStatusCode.OK && updateResponse.StatusCode != HttpStatusCode.Continue)
      {
        throw new Exception(string.Format("An error occurred while invoking the Twitter REST API [Response Code: {0}]", updateResponse.StatusCode));
      }
    }
  }

  public static class Extensions
  {
    public static string ToTweet(this string s)
    {
      if (string.IsNullOrEmpty(s) || s.Length < 140)
      {
        return s;
      }

      return s.Substring(0, 137) + "...";
    }
  }
}

다음과 같이 구성하십시오.

대상을 포함하는 어셈블리를 NLog에 알리십시오.

<extensions>
  <add assembly="NLogExtensions"/>
</extensions>

대상을 구성하십시오.

<targets>
    <target name="twitter" type="TwitterTarget" TwitterUserName="yourtwittername" TwitterPassword="yourtwitterpassword" layout="${longdate} ${logger} ${level} ${message}" />
</targets>

누군가 이것을 시도하고 성공하면, 발견 한 내용을 다시 게시하십시오.


트위터는 OAuth를 사용합니다 -.NET
Pat

7

외부 웹 사이트 / 데이터베이스에보고

응용 프로그램에서 사용자가 자주하지 않기 때문에 간단하고 자동으로 오류를보고하는 방법을 원했습니다. 내가 얻을 수있는 가장 쉬운 해결책은 공용 URL-입력을 받아서 데이터베이스에 저장할 수있는 웹 페이지-응용 프로그램 오류시 데이터를 보내는 것입니다. 그런 다음 개발자 나 스크립트로 데이터베이스를 검사하여 새로운 오류가 있는지 확인할 수 있습니다.

PHP로 웹 페이지를 작성하고 데이터를 저장할 mysql 데이터베이스, 사용자 및 테이블을 만들었습니다. 4 개의 사용자 변수, ID 및 타임 스탬프를 결정했습니다. 가능한 변수 (URL에 포함되거나 POST 데이터로)는 다음과 같습니다.

  • app (신청 명)
  • msg (메시지-예 : 예외가 발생했습니다 ...)
  • dev (개발자-예 : Pat)
  • src(소스 -이 앱은 예를 들어, 실행 된 시스템에 관련된 변수에서 올 것 Environment.MachineName또는 일부 등)
  • log (로그 파일 또는 자세한 메시지)

(모든 변수는 선택 사항이지만 설정되지 않은 경우 아무 것도보고되지 않으므로 웹 사이트 URL을 방문하면 db로 아무것도 전송되지 않습니다.)

데이터를 URL로 보내려면 NLog의 WebServicetarget을 사용했습니다 . (참고로, 나는 처음 에이 목표에 몇 가지 문제가 url있었습니다 /.

대체로 외부 앱에 탭을 유지하는 것은 나쁜 시스템이 아닙니다. (물론, 예의 바르게 행동하는 것은 사용자에게 민감한 데이터를보고 할 것이라고 알리고 옵트 인 / 아웃 할 수있는 방법을 제공하는 것입니다.)

MySQL 물건

(db 사용자는 INSERT자신의 데이터베이스에있는이 하나의 테이블에 대한 권한 만 갖습니다.)

CREATE TABLE `reports` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `ts` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `applicationName` text,
  `message` text,
  `developer` text,
  `source` text,
  `logData` longtext,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='storage place for reports from external applications'

웹 사이트 코드

(와 PHP 5.3 또는 5.2 PDO가 가능 , 파일은 index.php에서 /report폴더)

<?php
$app = $_REQUEST['app'];
$msg = $_REQUEST['msg'];
$dev = $_REQUEST['dev'];
$src = $_REQUEST['src'];
$log = $_REQUEST['log'];

$dbData =
    array(  ':app' => $app,
            ':msg' => $msg,
            ':dev' => $dev,
            ':src' => $src,
            ':log' => $log
    );
//print_r($dbData); // For debugging only! This could allow XSS attacks.
if(isEmpty($dbData)) die("No data provided");

try {
$db = new PDO("mysql:host=$host;dbname=reporting", "reporter", $pass, array(
    PDO::ATTR_PERSISTENT => true
));
$s = $db->prepare("INSERT INTO reporting.reports 
    (
    applicationName, 
    message, 
    developer, 
    source, 
    logData
    )
    VALUES
    (
    :app, 
    :msg, 
    :dev, 
    :src, 
    :log
    );"
    );
$s->execute($dbData);
print "Added report to database";
} catch (PDOException $e) {
// Sensitive information can be displayed if this exception isn't handled
//print "Error!: " . $e->getMessage() . "<br/>";
die("PDO error");
}

function isEmpty($array = array()) {
    foreach ($array as $element) {
        if (!empty($element)) {
            return false;
        }
    }
    return true;
}
?>

앱 코드 (NLog 구성 파일)

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      throwExceptions="true" internalLogToConsole="true" internalLogLevel="Warn" internalLogFile="nlog.log">
    <variable name="appTitle" value="My External App"/>
    <variable name="csvPath" value="${specialfolder:folder=Desktop:file=${appTitle} log.csv}"/>
    <variable name="developer" value="Pat"/>

    <targets async="true">
        <!--The following will keep the default number of log messages in a buffer and write out certain levels if there is an error and other levels if there is not. Messages that appeared before the error (in code) will be included, since they are buffered.-->
        <wrapper-target xsi:type="BufferingWrapper" name="smartLog">
            <wrapper-target xsi:type="PostFilteringWrapper">
                <target xsi:type="File" fileName="${csvPath}"
                archiveAboveSize="4194304" concurrentWrites="false" maxArchiveFiles="1" archiveNumbering="Sequence"
                >
                    <layout xsi:type="CsvLayout" delimiter="Comma" withHeader="false">
                        <column name="time" layout="${longdate}" />
                        <column name="level" layout="${level:upperCase=true}"/>
                        <column name="message" layout="${message}" />
                        <column name="callsite" layout="${callsite:includeSourcePath=true}" />
                        <column name="stacktrace" layout="${stacktrace:topFrames=10}" />
                        <column name="exception" layout="${exception:format=ToString}"/>
                        <!--<column name="logger" layout="${logger}"/>-->
                    </layout>
                </target>

                 <!--during normal execution only log certain messages--> 
                <defaultFilter>level >= LogLevel.Warn</defaultFilter>

                 <!--if there is at least one error, log everything from trace level--> 
                <when exists="level >= LogLevel.Error" filter="level >= LogLevel.Trace" />
            </wrapper-target>
        </wrapper-target>

        <target xsi:type="WebService" name="web"
                url="http://example.com/report" 
                methodName=""
                namespace=""
                protocol="HttpPost"
                >
            <parameter name="app" layout="${appTitle}"/>
            <parameter name="msg" layout="${message}"/>
            <parameter name="dev" layout="${developer}"/>
            <parameter name="src" layout="${environment:variable=UserName} (${windows-identity}) on ${machinename} running os ${environment:variable=OSVersion} with CLR v${environment:variable=Version}"/>
            <parameter name="log" layout="${file-contents:fileName=${csvPath}}"/>
        </target>

    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="smartLog"/>
        <logger name="*" minlevel="Error" writeTo="web"/>
    </rules>
</nlog>

참고 : 로그 파일 크기에 문제가있을 수 있지만 간단한 잘라 내기 방법을 찾지 못했습니다 (예 : la * nix 's tailcommand ).


이것은 하나의 프로젝트에서 작동했지만 다른 프로젝트에서는 url다음 과 같은 문제가 발생했습니다 . InnerException : System.InvalidCastException Message = 'System.String'에서 'System.Uri'로의 캐스트가 잘못되었습니다. Source = mscorlib StackTrace : System.Convert.ChangeType (Object 값, 형식 변환 형식)의 System.String.System.IConvertible.ToType (Type 형식, IFormatProvider 공급자)의 System.Convert.DefaultToType (IConvertible 값, 형식 targetType, IFormatProvider 공급자)에서 , IFormatProvider 제공 업체)
Pat

로그를 모니터링하고 오류가 발생했을 때 알림을 받으려는 경우 다른 옵션은 Twitter 대상입니다. 작성된 트위터이 appender이 링크를 참조 log4net : twitterappender.codeplex.com 이 논의 원래 블로그 포스팅은 여기에 있습니다 : caseywatson.com/2009/07/07/log4net-twitter-awesome은 이 비슷한 쓰기 뭔가 아주 쉬워야한다 NLog.
wageoghe

NLog TwitterTarget을 작성하는 데 장난을 쳤지 만 실제로 트윗을 게시하는 데 성공하지 못했습니다. 코드를 답변으로 게시했습니다. 원한다면 자유롭게 사용해보십시오.
wageoghe

6

조건부 레이아웃을 사용하여 다른 레이아웃으로 각 로그 수준을 기록하는 쉬운 방법

<variable name="VerboseLayout" value="${level:uppercase=true}: ${longdate} | ${logger}    : 
${when:when=level == LogLevel.Trace:inner=MONITOR_TRACE ${message}} 
${when:when=level == LogLevel.Debug:inner=MONITOR_DEBUG ${message}} 
${when:when=level == LogLevel.Info:inner=MONITOR_INFO ${message}} 
${when:when=level == LogLevel.Warn:inner=MONITOR_WARN ${message}} 
${when:when=level == LogLevel.Error:inner=MONITOR_ERROR ${message}} 
${when:when=level == LogLevel.Fatal:inner=MONITOR_CRITICAL ${message}} |     
${exception:format=tostring} | ${newline} ${newline}" />

구문 은 https://github.com/NLog/NLog/wiki/When-Filter 를 참조 하십시오.


4

Silverlight에서 로그

Silverlight와 함께 NLog를 사용하면 제공된 웹 서비스 를 통해 추적을 서버 측으로 보낼 수 있습니다 . 웹 서버를 사용할 수없는 경우 격리 저장소의 로컬 파일에 쓸 수도 있습니다. 자세한 내용은 여기 를 참조 하십시오 . 예를 들어 다음과 같이 자신을 목표로 삼으십시오.

namespace NLogTargets
{
    [Target("IsolatedStorageTarget")]
    public sealed class IsolatedStorageTarget : TargetWithLayout
    {
        IsolatedStorageFile _storageFile = null;
        string _fileName = "Nlog.log"; // Default. Configurable through the 'filename' attribute in nlog.config

        public IsolatedStorageTarget()
        {
        }

        ~IsolatedStorageTarget()
        {
            if (_storageFile != null)
            {
                _storageFile.Dispose();
                _storageFile = null;
            }
        }

        public string filename
        {
            set
            {
                _fileName = value; 
            }
            get
            {
                return _fileName;  
            }
         }

        protected override void Write(LogEventInfo logEvent)
        {
            try
            {
                writeToIsolatedStorage(this.Layout.Render(logEvent));
            }
            catch (Exception e)
            {
                // Not much to do about his....
            }
        }

        public void writeToIsolatedStorage(string msg)
        {
            if (_storageFile == null)
                _storageFile = IsolatedStorageFile.GetUserStoreForApplication();
            using (IsolatedStorageFile isolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                // The isolated storage is limited in size. So, when approaching the limit
                // simply purge the log file. (Yeah yeah, the file should be circular, I know...)
                if (_storageFile.AvailableFreeSpace < msg.Length * 100)
                {
                    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_fileName, FileMode.Truncate, FileAccess.Write, isolatedStorage))
                    { }
                }
                // Write to isolated storage
                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_fileName, FileMode.Append, FileAccess.Write, isolatedStorage))
                {
                    using (TextWriter writer = new StreamWriter(stream))
                    {
                        writer.WriteLine(msg);
                    }
                }
            }
        }
    } 
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.