最も有用なNLog構成[終了]


348

NLogでログを記録するための最良または最も有用な構成は何ですか?(これらは、有用である限り、単純でも複雑でもかまいません。)

特定のサイズでログファイルを自動的にロールオーバーする、例外があるかどうかにかかわらずレイアウト(ログメッセージ)を変更する、エラーが発生したときにログレベルをエスカレートするなどの例を考えています。

ここにいくつかのリンクがあります:


3
以下は、テストに基づくパフォーマンスチューニングのヒントです。deep
Neil

回答:


391

これらのいくつかは、厳密な構成の提案ではなく、一般的なNLog(またはログ)ヒントのカテゴリに分類されます。

ここに、SOからの一般的なロギングリンクをいくつか示します(これらのリンクの一部またはすべてはすでに見たことがあるかもしれません)。

log4net対Nlog

ロギングのベストプラクティス

伐採ファサードのポイントは何ですか?

ロガーがクラスごとにロガーの使用を推奨するのはなぜですか?

クラスに基づいてロガーに名前を付ける一般的なパターンを使用する Logger logger = LogManager.GetCurrentClassLogger()。これにより、ロガーに高度な粒度が与えられ、ロガーの構成に大きな柔軟性が与えられます(グローバルに、名前空間、特定のロガー名などで制御)。

必要に応じて、クラス名に基づかないロガーを使用してください。ロギングを個別に制御したい関数が1つあるかもしれません。たぶん、横断的なロギングの懸念(パフォーマンスロギング)があるかもしれません。

クラス名ベースのロギングを使用しない場合は、ロガーに何らかの階層構造(おそらく機能領域による)で名前を付けることを検討してください。これにより、構成の柔軟性を維持できます。たとえば、「データベース」機能領域、「分析」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 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」などの名前を付けることができます。

独自のレイアウトレンダラーを書くことを恐れないでください。設定は簡単で、独自のコンテキスト情報をログファイルに追加できます。たとえば、次のレイアウトレンダラー(2.0ではなくNLog 1.xに基づく)は、Trace.CorrelationManager.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はLayoutRendererラッパーを追加します。これにより、レイアウトレンダラーの出力に対して追加処理(空白のトリミング、大文字、小文字など)を実行できます。

NLogへの強い依存からコードを分離したい場合は、ロガーをラップすることを恐れないでください。ただし、正しくラップしてください。NLogのgithubリポジトリをラップする方法の例があります。ラップするもう1つの理由は、ログに記録された各メッセージに特定のコンテキスト情報を(LogEventInfo.Contextに入れることによって)自動的に追加することです。

NLog(またはその他のロギングフレームワーク)をラップ(または抽象化)することには長所と短所があります。少しの努力で、両側にあるSOに関する情報をたくさん見つけることができます。

ラッピングを検討している場合は、Common.Loggingの使用を検討してください。これはかなりうまく機能し、必要に応じて別のロギングフレームワークに簡単に切り替えることができます。また、ラッピングを検討している場合は、コンテキストオブジェクト(GDC、MDC、NDC)の処理方法を検討してください。Common.Loggingは現在、それらの抽象化をサポートしていませんが、追加する機能のキューにあると思われます。


3
すばらしい答えです。追加することの1つだけ、$ {machine}は$ {machinename}である必要があります。github.com/nlog/NLog/wiki/Layout-Renderersを参照してください。
リャン2013年

2
Common.Loggingをフォークし、不足している抽象化を追加しました。GitHub プロジェクトまたはNuGetを参照しください。
ダニーヴァロド2014年

自分のドキュメントでnlogに関する有益な情報を見つけることができませんでした。おそらくgithubの例を間違って調べていますか?知るか。
JARRRRG 2014年

APIでそのカスタムレンダラーを使用する方法(構成ファイルなし)?ここでは、だ、私が達成しようとしているものを。
InteXX

はい、わかった。NewLineレイアウトは、タスクを達成します。ここだ私が思い付きました。思っていたよりもずっとシンプルだと思います。
InteXX

65

例外の扱いを変える

例外が発生した場合、多くの場合、より多くの情報が必要になります。次の構成には、ファイルとコンソールの2つのターゲットがあり、例外情報があるかどうかに基づいてフィルタリングします。(編集: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 2010年

+1とてもいい。私はこれを長い間ブックマークしており、条件付きレイアウトに関して別のSOの質問から「Patのコメント」を参照しました。
eduncan911 2012

1
例外がログに記録されると、2回ログに記録されます(VerboseLayout部分)。
Tien Do

2
ルールminlevel = "Warn"を "file、fileAsException"に設定したため、プロジェクトで明日試してみましたが、すべてのログは最初にファイルターゲット(フィルターなし)でログに記録され、例外の場合(状態)fileAsExceptionでもログに記録されます。
Tien Do

3
@Tiendqああ、なるほど。これは理にかなっていますが、例外自体(詳細)は1度だけログに記録されます(ただし、メッセージは2度記録されます)。あなたは、おそらく追加することによってことを修正することができますcondition="length('${exception}')=0(または多分それはだ==し)target name="file"
パット

60

どうやら、NLogをGrowl for Windowsで使用できるようになりました

<?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 Growl for WindowsでのNLogトレースメッセージ Growl for WindowsでのNLogデバッグメッセージ Windows用GrowlでのNLog情報メッセージ NLogがGrowl for Windowsでメッセージを警告する Growl for WindowsでのNLogエラーメッセージ Windows向けGrowlでのNLogの致命的なメッセージ


再接続のために何をすべきか教えてもらえますか?ローカルホストでは問題なく機能しますが、ホストでIPアドレスを指定すると機能しません。
2013年

@ニール、ターゲットコンピューターのGrowlで「セキュリティ」設定を確認する必要があります。「LAN」通知を明示的に有効にする必要があり、パスワードを設定する必要がある場合があります(パスワードはNLogターゲットに追加する必要があります)。しかし、リモート通知が「ローカルマシン」の「オリジン」でGrowlに表示されるのが気に入らなかった。通知がどこで発生したかを知るために、ログエントリにホストを追加する必要があります。
ケニーエビット2014年

通知をローカルマシンで機能させることができますが、リモートでは機能しません。私のセキュリティ設定にはうなり声のパスワードがないので、追加したのはIPとポートだけでした。しかし、何も送信されません。
Jack Reilly 2017

1
このプロジェクトは100%死んでいます
開発者

28

XMLを介して、ただしプログラムでNLogを構成する

何?NLogに構成ファイルから読み取らせるのではなく、アプリから直接NLogにNLog XMLを指定できることをご存知ですか?ええ、できます。分散アプリがあり、どこでも同じ構成を使用したいとします。構成ファイルを各場所に保持して個別に維持することも、1つの場所を中心に維持して衛星の場所にプッシュすることもできますが、他にも多くのことを行うことができます。または、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

これがどれほど堅牢であるかはわかりませんが、この例は、このように構成しようとする可能性のある人々に役立つ出発点を提供します。


それは非常にうまく機能します...これを使用することを除いて、ロギングシステムを動的に再構成することはもはや不可能です。これは、外部ファイル(インクルード)にリンクする場合に特に
当てはまり

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

エラーの有無に応じて、さまざまなレベルのロギング

この例では、コードにエラーがある場合に詳細情報を取得できます。基本的に、それはメッセージをバッファリングし、特定の条件が満たされない限り(例えば、エラーが発生したため、ログレベルが> =エラーの場合)、特定のログレベル(警告など)のメッセージのみを出力します。ログレベル> =トレースからのすべてのメッセージ)。メッセージはバッファリングされるため、これにより、ErrorまたはErrorExceptionがログに記録される前に何が起こったかに関するトレース情報を収集できます-非常に便利です!

はソースコードの例からこれを採用しました。(私のものはAspNetBufferingWrapperASPアプリではないため)省略したため、最初にスローされました-PostFilteringWrapperにはバッファーされたターゲットが必要であることがわかりましたtarget-ref上記のリンクの例で使用されている要素はNLog 1.0では使用できないことに注意してください(.NET 4.0アプリで1.0リフレッシュを使用しています)。ターゲットをラッパーブロック内に配置する必要があります。また、論理構文(つまり、大なり記号または小なり記号、<および>)は、それらの記号(つまり&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の一部のバージョン(モノおよび2.0の場合)では、StackOverflowExceptionが発生しますが、他のバージョンでは発生しません(NLog 1の更新)。
パット

オーバーフローについて-レイアウトがCSVタイプであることが原因のようです-通常のレイアウトを行っても問題ありません。
パット

fileAsCsv target-refは何のためのものですか?この例をNLog v2.0.0.2000に対して機能させようとしていますが、今のところ失敗しています。
Peter Mounce

@PeterMounce fileAsCsvtarget-refは、私のテストの成果物です。NLog 2には、CsvLayoutsにNLog 1 / Refreshにはなかった問題があった/あると思います。
パット

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
パット

10

Twitterにログイン

log4net Twitter Appenderに関するこの投稿に基づく、私はNLog Twitterターゲット(2.0ではなくNLog 1.0リフレッシュを使用)を書くことに自分の手を試してみると思いました。残念ながら、これまでのところ、ツイートを実際に投稿することはできません。私のコード、Twitter、当社のインターネット接続/ファイアウォール、または何が問題なのかわかりません。誰かがそれを試すことに興味がある場合に備えて、ここにコードを投稿しています。3つの異なる "Post"メソッドがあることに注意してください。最初に試したのはPostMessageToTwitterです。PostMessageToTwitterは、元の投稿のPostLoggingEventと基本的に同じです。これを使用すると、401例外が発生します。PostMessageBasicも同じ例外を受け取ります。PostMessageはエラーなしで実行されますが、メッセージはまだTwitterを構成しません。PostMessageとPostMessageBasicは、SOでここで見つけた例に基づいています。

FYI -私はちょうど今では答えに@Jasonディラーによるコメント見つかっこの記事さえずりが基本認証「来月」をオフにしようとしていることを述べています。これは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>

誰かがこれを試して成功した場合は、調査結果を投稿してください。


TwitterはOAuthを使用-.NET
Pat

7

外部のウェブサイト/データベースへの報告

私は、アプリケーションからエラーを(ユーザーが報告しないことが多いため)簡単かつ自動的に報告する方法を望んでいました。私が思いつくことができる最も簡単なソリューションは、アプリケーションのエラー時にデータが送信されるパブリックURL(入力を取得してデータベースに保存できるWebページ)でした。(その後、データベースは、新しいエラーがあるかどうかを知るために、開発者またはスクリプトによってチェックされます。)

PHPでWebページを作成し、データを格納するmysqlデータベース、ユーザー、およびテーブルを作成しました。4つのユーザー変数、ID、およびタイムスタンプを決定しました。可能な変数(URLに含まれるか、POSTデータとして):

  • app (アプリケーション名)
  • msg (メッセージ-例:例外が発生しました...)
  • dev (開発者-パットなど)
  • src(ソース-これは、アプリが実行されているマシンに関連する変数などから取得されますEnvironment.MachineName
  • log (ログファイルまたは詳細メッセージ)

(すべての変数はオプションですが、設定されていない場合は何も報告されません。そのため、WebサイトのURLにアクセスしただけでは、データベースには何も送信されません。)

データをURLに送信するために、NLogのWebServiceターゲットを使用しました。(注意:最初はこのターゲットにいくつかの問題がありました。ソースを見て初めて、でurl終わることができないことがわかりました/。)

全体として、それは外部アプリを監視するための悪いシステムではありません。(もちろん、慎重に行うべきことは、機密性の高いデータを報告することをユーザー通知し、オプトイン/オプトアウトする方法をユーザー提供することです。)

MySQLのもの

(dbユーザーはINSERT、自身のデータベース内のこの1つのテーブルに対してのみ特権を持っています。)

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のtailコマンド)を理解していません。


これは1つのプロジェクトで機能しましたが、他のプロジェクトでは次の問題がありましたurl:InnerException:System.InvalidCastException Message =「System.String」から「System.Uri」への無効なキャスト。Source = mscorlib StackTrace:System.Convert.DefaultToType(IConvertible value、Type targetType、IFormatProvider provider)at System.String.System.IConvertible.ToType(Type type、IFormatProvider provider)at System.Convert.ChangeType(Object value、Type conversionType 、IFormatProviderプロバイダー)
Pat

ログを監視し、エラーが発生したときに通知を受けることができるようにする場合の別のオプションは、Twitterターゲットです。:log4netのために書かれたTwitterのアペンダのために、このリンクを参照してください twitterappender.codeplex.com オリジナルのブログ投稿はこれを議論はここにある: caseywatson.com/2009/07/07/log4net-twitter-awesomeは、 それは書き込みにかなり簡単のために類似したものになるはずですNLog。
wageoghe 2010

私はNLog TwitterTargetの作成に騙されましたが、実際にツイートを投稿することに成功していません。回答としてコードを投稿しました。よろしければ試してみてください。
wageoghe 2010

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を使用する場合、提供された Webサービスを介してサーバー側にトレースを送信できます。分離ストレージのローカルファイルに書き込むこともできます。これは、Webサーバーが利用できない場合に便利です。詳細についてはここを参照てください。つまり、次のようなものを使用して自分をターゲットにします。

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.