C# - NLog

특징

  • 오픈소스 닷넷 플랫폼 로그 라이브러리
  • .NET Compact, mono도 지원
  • 사용이 쉽고, 설정은 설정 파일과 소스 코드를 통한 2가지 방법 제공.
  • 옵션 지정으로 버퍼링, 비동기, 로드 밸런싱, 장애대처 등을 할 수 있다.
  • 출력 옵션
    • Files - single file or multiple, with automatic file naming and archival
    • Event Log - local or remote
    • Database - store your logs in databases supported by .NET
    • Network - using TCP, UDP, SOAP, MSMQ protocols
    • Command-line console - including color coding of messages
    • E-mail - you can receive emails whenever application errors occur
    • ASP.NET trace 등등…
  • NuGet 지원. [http://www.nuget.org/packages/NLog]
  • 로그 뷰어. [https://github.com/nlog/nlog/wiki/Tools]

설치

  • 가장 쉬운 방법은 위에 나왔듯이 Nuget으로 설치한다.
  • 주의할 점은 Nuget에서 NLog뿐만이 아닌 ‘NLog Configuration’도 설치한다.
    • NLog Configuration는 NLog 설정 파일을(NLog.config) 설치해준다.
  • NLog.config 파일에 로그 설정을 한다.
  • File-Target 설명 [https://github.com/nlog/NLog/wiki/File-target]

기본 사용

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

  <!--
  See https://github.com/nlog/nlog/wiki/Configuration-file
  for information on customizing logging rules and outputs.
   -->
  <targets>
    <target name="console" xsi:type="ColoredConsole" layout="${date:format=HH\:mm\:ss}| [TID:${threadid}] | ${stacktrace} | ${message}" />
    <target name="file" xsi:type="File" fileName="${basedir}/Logs/${date:format=MMddhhmmss}.log" layout="[${date}] [TID:${threadid}] [{stacktrace}]: ${message}" />
  </targets>

  <rules>
    <logger name="*" minlevel="Info" writeTo="file" />
    <logger name="*" minlevel="Info" writeTo="console" />
  </rules>
</nlog>
  • 사용 코드
using NLog;

public class LoggerClass
{
  private static Logger Logger = LogManager.GetCurrentClassLogger();

  public static void NLogInfo(string message)
  {
      Logger.Info(message);
  }

  public static void NLogFatal(string message)
  {
      Logger.Fatal(message);
  }
}

예외 로그로 남기기

// 예외 발생
try {
    int i = 0;
    i = 1 / i;
}
catch (Exception ex)
{
    // 예외 로그 출력
    _logger.ErrorException("0 나누기 에러:" , ex);
}


<target name="file" xsi:type="File"
layout="${message} ${exception:format=tostring}"
fileName="${basedir}/log.txt" />

로그 설정 예제: 파일 크기 로테이션, 리치텍스트 컨트룰 출력, 특정 문자 포함 로그만 출력

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

<!--출력(Target) 설정-->
<targets>

    <!--파일 출력(10 KByte 마다 로테이션)-->
    <target name="file" xsi:type="File"
    layout="${longdate} ${level:uppercase=true:padding=-5} [${threadid}] ${logger} - ${message} ${exception:format=tostring}"
    fileName="${basedir}/logs/log.txt"
    archiveFileName="${basedir}/logs/${date:format=yyyyMMdd}/log.{###}.txt"  <!--로테이션으로 만들어진 로그 파일 이름 형식-->
    archiveAboveSize="10240"
    archiveNumbering="Sequence"
    maxArchiveFiles="20" />

    <!-- 폼의 리치 텍스트 컨트롤(색 입히기)-->
    <target name="rich" xsi:type="RichTextBox"
    formName="Form1"
    controlName="richTextBox1"
    useDefaultRowColoringRules="true" />

    <!--디버그/출력 윈도우-->
    <target name="debugger" xsi:type="Debugger"/>

    <!--「치명적」 이라는 문자를 포함 시에만 출력하는 필터링-->
    <target name="eventlog" xsi:type="FilteringWrapper"
        condition="contains('${message}','치명적')">
        <!--이벤트 로그-->
        <target xsi:type="EventLog"
            source="NLog Sample"
            log="Application" />
    </target>

</targets>

<!--출력 룰 설정-->
<rules>
    <logger name="Sample.*" minlevel="Info" writeTo="file,rich,debugger" />
    <logger name="*" levels="Error,Fatal" writeTo="eventlog" />
</rules>
</nlog>

Logger 이름을 로그 출력 파일 이름으로 설정

  • 로그 파일 이름이 현재 시간이 되도록 로거 이름을 현재 시간으로 설정
public static Logger Logger = LogManager.GetLogger(DateTime.Now.ToString());
</source>
<source lang="cpp">
<target name="file" xsi:type="File"
            fileName="${basedir}/Logs/${logger}.log"
            layout="[${date}] [TID:${threadid}] [${stacktrace}]: ${message}" />
 </targets>

##로그 파일 크기가 넘어서면 새로운 로그 파일 만들기

  • 옵션 중 timeToSleepBetweenBatches의 기본은 50. 만약 0으로 설정하면 CPU 엄청 먹으므로 절대 0으로 하면 안된다
<?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">

  <!--
  See https://github.com/nlog/nlog/wiki/Configuration-file
  for information on customizing logging rules and outputs.
   -->
  <targets>
    <target name="console" xsi:type="ColoredConsole" layout="${date:format=HH\:mm\:ss}| [TID:${threadid}] | ${stacktrace} | ${message}" />
    <target name="file" xsi:type="File"
            fileName="${basedir}/Logs/${logger}.log"
            archiveAboveSize="1000"
            archiveFileName="${basedir}/Logs/${date:format=MMddHHmm}/${shortdate}.{#####}.log"
            archiveNumbering="Sequence"
            layout="[${date}] [TID:${threadid}] [${stacktrace}]: ${message}" />
  </targets>

  <rules>
    <logger name="*" minlevel="Info" writeTo="file" />
    <logger name="*" minlevel="Info" writeTo="console" />
  </rules>
</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">

  <!--
  See https://github.com/nlog/nlog/wiki/Configuration-file
  for information on customizing logging rules and outputs.
   -->
  <targets>
    <!--<target name="console" xsi:type="ColoredConsole" layout="${date:format=HH\:mm\:ss}| [TID:${threadid}] | ${message}" />-->

    <target name="AsyncConsoleLog"
            xsi:type="AsyncWrapper" overflowAction="Block" queueLimit="1000000" batchSize="1000" timeToSleepBetweenBatches="1">
      <target name="console" xsi:type="ColoredConsole" layout="${date:format=HH\:mm\:ss}| [TID:${threadid}] | ${message}" />
    </target>

    <target name="AsyncInfoLog"
            xsi:type="AsyncWrapper" overflowAction="Block" queueLimit="1000000" batchSize="1000" timeToSleepBetweenBatches="1">
      <target name="InfoFile" xsi:type="File"
            fileName="${basedir}/Logs/Info_${logger}.log"
            archiveAboveSize="128000000"
            archiveFileName="${basedir}/Logs/Info_${date:format=MMddHHmm}/${shortdate}.{#####}.log"
            archiveNumbering="Sequence"
            concurrentWrites="false"
            layout="[${date}] [TID:${threadid}] [${stacktrace}] ${message}" />
    </target>

    <target name="AsyncErrorLog"
            xsi:type="AsyncWrapper" overflowAction="Block" queueLimit="1000000" batchSize="1000" timeToSleepBetweenBatches="1">
      <target name="ErrorFile" xsi:type="File"
            fileName="${basedir}/Logs/Error_${logger}.log"
            archiveAboveSize="128000000"
            archiveFileName="${basedir}/Logs/Error_${date:format=MMddHHmm}/${shortdate}.{#####}.log"
            archiveNumbering="Sequence"
            concurrentWrites="false"
            layout="[${date}] [TID:${threadid}] [${stacktrace}] ${message}" />
    </target>

  </targets>

  <rules>
    <logger name="*" minlevel="Info" maxlevel="Info" writeTo="AsyncInfoLog" />
    <logger name="*" minlevel="Error" writeTo="AsyncErrorLog" />

    <!-- 서비스 시에는 콘솔은 주석 처리하자 -->
    <logger name="*" minlevel="Info" writeTo="AsyncConsoleLog" />
  </rules>
</nlog>

csv 포맷으로 출력하기

<target name="AsyncInfoLog"
        xsi:type="AsyncWrapper" overflowAction="Block" queueLimit="1000000" batchSize="1000" timeToSleepBetweenBatches="1">
  <target name="InfoFile" xsi:type="File"
        fileName="${basedir}/Logs/Info_${logger}.log"
        archiveAboveSize="128000000"
        archiveFileName="${basedir}/Logs/Info_${date:format=MMddHHmm}/${shortdate}.{#####}.log"
        archiveNumbering="Sequence"
        concurrentWrites="false">
        <layout xsi:type="CsvLayout">
          <column name="time" layout="${date}" />
          <column name="tid" layout="${threadid}"/>
          <column name="stack" layout="${stacktrace}"/>
          <column name="message" layout="${message}" />
        </layout>
  </target>
</target>
time,tid,stack,message
2015/07/06 15:27:40.398,1,Program.Main => FileLogger.Info,[24]서버 시작 준비 ~~~


메시지 안에서 , 을 사용한 경우 메시지를 "로 묶는다
2015/07/06 15:27:43.428,1,Program.Main => FileLogger.Info,"[47]최소 워커 스레드 수: 8, 최소 IO 스레드 수:8 | 최대 워커 스레드 수: 32767, 최대 IO 스레드 수:1000"

릴리즈 빌드에서는 로그를 완전 제거

  • Logger.ConditionalTrace(“entering method {0}”, methodname);

참고

  • 본인이 만든 문서 [http://www.slideshare.net/jacking/n-log]
  • NLog 관련 글 모음 [https://github.com/nlog/nlog/wiki/Web-resources]
  • (일어)NLog 자주 사용하는 레이아웃
  • (일어)NLog 출력하는 파일을 나누기
  • How to NLog (2.1 & 3.1) with VisualStudio 2013 [http://www.codeproject.com/Tips/749612/How-to-NLog-with-VisualStudio]
  • .NET low latency logging. Part 1 - Testing environment, Sample application, Best performance! [http://deep-depth.blogspot.kr/2014/01/choose-solution-for-low-latency-logging.html]
  • .NET low latency logging. Part 2 - NLog performance [http://deep-depth.blogspot.kr/2014/01/net-low-latency-logging-part-2-nlog.html]
  • .NET low latency logging. Part 3 - log4net performance [http://deep-depth.blogspot.kr/2014/01/net-low-latency-logging-part-3-log4net.html]

이 글은 2019-04-01에 작성되었습니다.