programing

가장 유용한 NLog 구성

iphone6s 2023. 5. 2. 22:28
반응형

가장 유용한 NLog 구성

NLog를 사용한 로깅에 가장 적합하거나 가장 유용한 구성은 무엇입니까? (도움이 되는 한 단순하거나 복잡할 수 있습니다.)

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

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

이 중 일부는 엄격한 구성 제안이 아닌 일반 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) 또는 하위 영역(데이터베이스)별로 로깅을 구성할 수 있습니다.연결 등).

로거에는 다음과 같은 다양한 구성 옵션이 있습니다.

<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 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", "Duesday.log" 등으로 지정할 수 있습니다.

자신만의 레이아웃 렌더러를 작성하는 것을 두려워하지 마십시오.구성을 통해 사용자 자신의 컨텍스트 정보를 로그 파일에 추가할 수 있습니다.예를 들어 추적을 추가할 수 있는 레이아웃 렌더러(2.0이 아닌 NLog 1.x 기반)가 있습니다.상관 관계 관리자.로그에 대한 ActivityId:

  [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은 레이아웃 렌더러의 출력에 대해 추가 처리를 수행할 수 있는 레이아웃 렌더러 래퍼를 추가합니다(예: 공백 트리밍, 대문자, 소문자 등).

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

NLog(또는 해당 사항에 대한 다른 로깅 프레임워크)를 래핑(또는 추상화)하는 것에는 장단점이 있습니다.조금만 노력하면 SO에 대한 많은 정보를 확인할 수 있습니다.

포장을 고려 중인 경우 공통을 사용하는 것이 좋습니다.로깅.잘 작동하며 원하는 경우 다른 로깅 프레임워크로 쉽게 전환할 수 있습니다.또한 래핑을 고려 중인 경우 컨텍스트 개체(GDC, MDC, NDC)를 어떻게 처리할지 생각해 보십시오.흔한.로깅은 현재 추상화를 지원하지 않지만 추가할 기능 대기열에 있는 것으로 추정됩니다.

예외를 다르게 처리

우리는 종종 예외가 있을 때 더 많은 정보를 얻고자 합니다.다음 구성에는 예외 정보가 있는지 여부를 필터링하는 파일과 콘솔이라는 두 가지 대상이 있습니다. (편집: 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>

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

Windows용 Growl을 사용한 NLog Windows용 Growl을 사용한 NLog 추적 메시지 Windows용 Growl을 사용한 NLog 디버그 메시지 Windows용 Growl이 포함된 NLog 정보 메시지 Windows용 Growl이 포함된 NLog 경고 메시지 Windows용 Growl과 함께 NLog 오류 메시지가 표시 Windows용 Growl과 함께 NLog 치명적인 메시지

XML을 통해 NLog를 구성하지만 프로그래밍 방식으로 구성

네? 구성 파일에서 NLog를 읽는 대신 앱에서 NLog XML을 직접 지정할 수 있다는 것을 알고 계십니까?뭐, 할 수 있어요.분산 앱이 있고 모든 곳에서 동일한 구성을 사용하려고 한다고 가정해 보겠습니다.구성 파일을 각 위치에 유지하고 별도로 유지하거나, 중앙 위치에 유지한 후 위성 위치로 밀어넣거나, 다른 많은 작업을 수행할 수 있습니다.또는 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

이 방법이 얼마나 강력한지는 모르겠지만, 이 예제는 이러한 구성을 시도하려는 사용자들에게 유용한 시작점을 제공합니다.

오류 여부에 따라 다양한 수준 기록

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

는 이것을 소스 코드의 예제에서 수정했습니다.나는 처음에 그것을 빼먹었기 때문에 던져졌습니다.AspNetBufferingWrapper(내 것은 ASP 앱이 아니기 때문에) - PostFilteringWrapper에는 버퍼링된 대상이 필요한 것으로 나타났습니다.참고:target-ref 1할 수 0하여 NLog 1을 사용합니다).NET 4.0 앱); 대상을 래퍼 블록 안에 넣어야 합니다. 구문 기호보다 < 및 >)은 해당 "", "XML 이스케이프")가.&gt;그리고.&lt;그렇지 않으면 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 - 로그 파일의 헤더 섹션 생성

머리글 추가:

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

헤더 및 파일 레이아웃을 정의합니다.

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

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

Twitter에 로그인

log4net Twitter Appender에 대한 게시물을 바탕으로, 저는 NLog Twitter Target(2.0이 아닌 NLog 1.0 리프레시 사용)을 작성해 보려고 했습니다.아아, 지금까지 저는 트위터를 성공적으로 게시하지 못했습니다.제 코드, 트위터, 저희 회사 인터넷 연결/방화벽 등에 이상이 있는지 모르겠습니다.혹시 누군가 시도해보고 싶어할까봐 코드를 여기에 올립니다.세 가지 다른 "포스트" 방법이 있습니다.첫 번째로 시도한 것은 PostMessageToTwitter입니다.PostMessageToTwitter는 원래 게시물의 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>

만약 누군가가 이것을 사용해보고 성공한다면, 여러분의 발견을 다시 게시하세요.

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

<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 을 참조하십시오.

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

저는 사용자가 애플리케이션에서 오류를 쉽게 자동으로 보고할 수 있는 방법을 원했습니다.제가 생각해낼 수 있는 가장 쉬운 해결책은 애플리케이션 오류 시 데이터를 전송하는 공개 URL, 즉 입력을 받아 데이터베이스에 저장할 수 있는 웹 페이지였습니다. (데이터베이스는 개발자나 스크립트를 통해 새로운 오류가 있는지 확인할 수 있습니다.)

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

  • app(응용프로그램 이름)
  • msg(예: 예).예외 발생...)
  • dev(개발자 - 예: 팻)
  • src(source - 이는 앱이 실행 중인 컴퓨터와 관련된 변수에서 온 것입니다.Environment.MachineName또는 일부)
  • log(로그 파일 또는 상세 메시지)

(모든 변수는 선택사항이지만 설정되지 않은 변수는 보고되지 않으므로 웹사이트 URL만 방문해도 DB로 전송되지 않습니다.)

URL로 데이터를 전송하기 위해 NLog의 target을 사용했습니다.(참고로 처음에는 이 대상에 대해 몇 가지 문제가 있었습니다.출처를 보고 나서야 제가 알아낸 것은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'

웹사이트 코드

(PDO가 활성화된 PHP 5.3 또는 5.2, 파일은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의 명령)을 찾지 못했습니다.

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);
                    }
                }
            }
        }
    } 
}

언급URL : https://stackoverflow.com/questions/4091606/most-useful-nlog-configurations

반응형