2014年07月27日

ログ 仕様検討の際に

ログの仕様を考える



始めに

システム開発では、非機能要件であるログの仕様が開発初期段階に提示されることはあまりない。
実装に入るまでの主な関心事が機能要件の策定にあることや、ログの仕様を決めるにはリリース後の保守運用まで勘案する必要があるからである。
それでも、出戻り作業とならないためには、なるべく早い時期に決めてしまいたい。そうしたログの仕様を検討する際には実際に実装を担当する側の意見を求められる場合は多い。ここでは検討を要する項目を纏めてみた。

目的

一口にログといってもいろいろとある。開発者側としてはエラーログデバッグログが重要であろうし、運用担当側からは操作ログアクセスログが必要な場合もある。その他にも、機能要件としての監査ログパフォーマンスログセキュリティログなどもある。
何のためにログを取得するのかを明確にすることが仕様策定への第一歩となる。

SOX法

上場企業を対象とした財務およびその関連システムを構築する場合はSOX法(金融商品取引法24条の4)の対応が必要となる。
※改竄されていない正確な生のログが一元管理され、検索や集計といったモニタリングが正当に運用される必要がある。
このような要件はログの仕様を考える上でSOX法対象外のシステム開発でもとても参考になります。


改竄抑止と暗号化

ログをローカルファイル等に出力する場合、それを読んだり書き換えたりすることは比較的容易であるので注意が必要である。
詳細レベルで取得している場合などでは個人情報に関するものが含まれていたり、SQL文からデータベースのテーブル構成が漏れてしまう場合もある。
また、特に監査ログ(オーディットログ)などでは、取得しているログが改竄や編集されていないことを保証する必要があったりする。
そのため、平文ではなく暗号化や難読化等の必要有無に関して検討する必要がある。

取得契機と責務

何の契機でログを採取するのかは重要である。画面上のボタンを押下したとか画面遷移したといったユーザ操作や、他システムからのデータ取り込みなどの入出力、画面層から業務ロジック層への処理委譲のような内部トレース、データベースや帳票出力のようなミドルウェア呼び出し、異常系や例外発生時等々。どのような契機でログを取得するかを決め、それに沿って実装する必要がある。
また、そのログ出力処理を各実装担当者が逐一実装していくのか、プロジェクトで使用する共通部品や共通基盤(フレームワーク)側で担うのかの責務分担を決める必要もある。

ログのコスト

ログを出力するコードを記述することは、当然に実装コストであり、ソースコードの可読性を低下させる原因にもなる。
また、実行時にはログ機能自身も処理の一種なので、当然にリソースを消費する。大量に出力すればその分だけパフォーマンスが劣化することは避けられない。
但し、ログ取得の責務を共通部品・共通基盤(フレームワーク)側に振ったり、出力用文言とソースコメントとを兼用することなどにより実装コスト削減を図ったり、3rd製のライブラリを使用することや非同期化・別プロセス化等によりパフォーマンスの影響を抑える実装は充分に可能である。

※ログは取れるだけ取っておいて、取得したログを表示するツール側でフィルタリングする傾向にあるように思う。

出力内容

時刻・場所・ユーザID・操作対象ID・スレッドID・重要度・カテゴリ・任意文字列・等々

何を出力するか、その情報はどこで取得するか(共通部品側で付加するのか、パラメタとして引き渡すのか)など。

出力文字の定型化

「{0}を開始しました。」「{0}を開始」「Start : {0}」といった文言の揺れを抑止するためにリソースとして文字列を用意する場合が多い。
また、このような設定は外部リソースとする場合が多い。

※ソースコード上に即値として定義したりアセンブリリースとして埋め込んだりせずに、外部リソースとして定義する方法がとられる場合が多い。実装最終盤に文言の揺れを一括して確認修正するためである。しかし、この定義に問題がある場合に、その旨のログそのものが出力されないといった致命的不具合となる場合があるので要注意。

設定ファイル

ログ出力用のライブラリは、出力レベルや出力先や出力文字列などの設定をアプリケーション構成ファイルやウェブ構成ファイルで定義可能となっている。これらはソースコードを修正しなくても設定変更を可能とするためである。

一般的に、構成ファイルはXML形式の平文であり、特別な知識がなくても編集可能であったりする。クライアントアプリケーションをユーザ環境で実行するシステムなどでは、設定変更の要件がないのならソースコードで行う方がよい場合もある。
※現在出回っている殆どのログ用ライブラリはその設定を構成ファイルで行るが、同様のことは設定ファイルを介さずソースコード上でも実装が可能な仕組みとなっている。

出力先

ファイルやデータベースの他、イベントログ・コンソール・メール・ネットワーク(ウェブサービス等)がある。
デバッグログはコンソール、通常のログはファイル、システム異常時はメールといった混在構成も可能である。

出力レベル

TraceSource(Standard Library) : Off,Critical,Error,Warning,Information,Verbose,(ActivityTracing)
Logging Application Block(Enterprize Library) : Off,Critical,Error,Warning,Information,Verbose
Log4net : Off,All,Fatal,Error,Warn,Info,Debug,Trace
NLog : Off,Fatal,Error,Warn,Info,Debug,Trace

上記は、主なログ出力用ライブラリに定義されている出力レベルの例である。
どういう場合に、どの出力レベルを使用するかはシステムとして統一されている必要がある。そのために早期の実装指針のとりまとめが必要である。

※開発時はAll(Debug)、リリース時はInfoレベル以上、安定稼働後はFatal(Critical)レベルのみのログを取得するよう設定を切り替えるとう運用をリソースが乏しい時代には行われていたが、近時は運用時は常にInfoレベルまでのログを取得し、それを使用(表示)する際のフィルタとしての使われ方に変わってきてる。らしい。賛否あり。

非同期対応

2つ考慮が必要。
一つは、スレッドセーフであること。つまり、ログ出力機能自身がマルチスレッドに対応している必要がある。

二つめは、パフォーマンスを考慮したバッファリング対応。DBアクセスはもちろんのこと、ローカルディスクへのフラッシュでもそれなりにコストがかかる。通常のログはメモリ内に保持してアイドル時等に出力(登録)するなど機能要件側の処理を邪魔しないように実装する必要がある。
但し、プロセスが終了するような例外系の場合は即時フラッシュしないと必要な情報が取得できない。

保守(保存期間やメンテナンス)

ログの保存期間や保存方法についても取り決める必要がある。保存期間経過後のログを消去(破棄)する仕組みも必要。
ファイルへ出力する場合はファイルサイズや日付等によるローリング(切替)が必要となる。
また、ファイルの出力先がローカル端末である場合、そららのログを収集し一元化するための何らかの処理も必要となる。

保守用ツール

大量に収集されたログから必要な情報を検索したり、暗号化された文字列を復号化するようなビューワが必要であろう。
また、ローカル端末に出力されたログファイルを収集したりRDB等に登録するツールや、指定期日経過後に削除するものなど、ログをメンテナンスしていくためのツールが必要となる場合がある。

他システムとの連携

既存の保守用ツールからの要請やログ管理用の3rd製品の要請などによりログ仕様が決まる場合がある。
大規模なシステムでは関連するアプリケーション全てで準拠すべき統一仕様を策定している場合があるし、もしくは策定する必要があるか要検討であろう。
データベースやサーバーやミドルウェアや依存ライブラリ等がそれら自身でログ出力を行っている場合は多い。同じ内容のログを取得する必要があるのかの検討も必要。

posted by RR at 11:27 | Comment(0) | ログ | このブログの読者になる | 更新情報をチェックする

ログ 標準ライブラリで提供されている機能

DebugとTrace

最も手軽なので現在でもよく使用されている機能である。
ビルドオプションでDEBUG定数・TRACE定数の定義の有無により実行有無の指定ができる。
通常はリリースビルド時はDEBUG定数の定義は行われない。(※構成の変更は可能)
デフォルトの設定では出力ウィンドウにのみ出力される。
ファイル等への出力はリスナを登録することにより行う。
リスナの登録は構成ファイルでも行える。
以下はファイル出力用リスナの登録をコードで行うサンプル。
using System.Diagnostics;
public static class LoggerSample
{
    // コンストラクタ
    static LoggerSample()
    {
        // リスナはDebugもTraceも同じコンテナに入るので、どちらかに登録すればよい
        TextWriterTraceListener twtl = new TextWriterTraceListener("TraceListener.log","TraceLog");
        System.Diagnostics.Trace.Listeners.Add(twtl);
        System.Diagnostics.Trace.AutoFlush = true;
    }

    public static void Debug(string message)
    {
        System.Diagnostics.Debug.WriteLine(message);
    }

    public static void Trace(string message)
    {
        System.Diagnostics.Trace.WriteLine(message);
    }
}

TraceSource

出力レベルを指定したログ出力が可能。
TraceやDebugと同様に、リスナを登録して使用する。
以下はファイル出力のサンプル。
リスナの登録は構成ファイルでも行える。
using System.Diagnostics;
public static class LoggerSample
{
    static TraceSource traceSource;

    static LoggerSample()
    {
        // トレースソースのインスタンスを生成
        traceSource = new TraceSource("traceSource", SourceLevels.All);
        // リスナを生成しトレースソースに登録
        TextWriterTraceListener twtl = new TextWriterTraceListener("TraceSourceListener.log", "TraceSourceLog");
        traceSource.Listeners.Add(twtl);
            
   public static void TraceSourceInformatiton(string message)
    {
       // Infoレベルでの書き込み
        traceSource.TraceEvent(TraceEventType.Information, 0,  message);
        traceSource.Flush();
    }
}

FileRecordSequence

3.0から導入されたレコード指向シーケンシャルIOシステム用のログクラス。
ファイルシステム内の単一ファイルに出力するたのFileRecordSequenceクラスとCLFS(Common Log File System)に出力するためのLogRecordSequenceクラスとが提供されている。
下記は単一ファイルに出力するサンプルコードである。文字列をバイト配列に変換する処理が介在するので非常にパフォーマンスが悪い。
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Log; // System.IO.Log.dll への参照の追加が必要
using System.Text;

    public static partial class LoggerSample
    {
       static FileRecordSequence sequence = new FileRecordSequence(@"FileRecordSequence.log", FileAccess.ReadWrite);

       public static void Record(string message)
       {
             sequence.Append(CreateData(message), SequenceNumber.Invalid, SequenceNumber.Invalid, RecordAppendOptions.ForceFlush);
    }

        private static IList<ArraySegment<byte>> CreateData(string str)
        {
            Encoding enc = Encoding.Unicode;

            byte[] array = enc.GetBytes(str);

            ArraySegment<byte>[] segments = new ArraySegment<byte>[1];
            segments[0] = new ArraySegment<byte>(array);

            return Array.AsReadOnly<ArraySegment<byte>>(segments);
        }

posted by RR at 20:04 | Comment(0) | ログ | このブログの読者になる | 更新情報をチェックする

ログ Enterprise Library 6.0 Log Application Block

Enterprise Libraryとは

マイクロソフトが無料で提供しているライブラリです。
いろんな機能が提供されており、その全部または一部を使用することができます。
ここでは Log Application Block を使用したサンプルを提示します。
なお、リスナーの登録は通常はアプリケーション構成ファイルにより行います。
これを編集するためのツールも同梱されています。
以下ではコード上で行っています。前版からその方法が大きく変更になりましたが、本家サイトのサンプルは古いままなので要注意です(2014/07/25)。

御本家サイト

https://entlib.codeplex.com/

サンプルコード

using System.Diagnostics;
// Add reference to Microsoft.Practices.EnterpriseLibrary.Logging.dll
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;

    public static class LogSample
    {
        static LogWriter writer;

        static LogSample()
        {
            var formatter = new TextFormatter("{message}");
            var listener = new FlatFileTraceListener(@"EntLib.log", null, null, formatter);
 
            var config = new LoggingConfiguration();
            config.AddLogSource("FileListener", SourceLevels.All, true)
                .AddTraceListener(listener);

            writer = new LogWriter(config);
                
        }

        public static void Write(string message)
        {
            if(writer.IsLoggingEnabled())
            {
                writer.Write(message);
              // 以下のようにLogEntryを生成することにより出力レベル等の詳細な設定も可能
              //var entry = new LogEntry()
                //{
                //    Message = message,
                //    Severity = System.Diagnostics.TraceEventType.Information
                //};

                //writer.Write(entry);
            }
        }
posted by RR at 20:27 | Comment(0) | ログ | このブログの読者になる | 更新情報をチェックする

ログ Log4net

Log4net

無料で、高機能で、高性能でオープンソースで、歴史も深く、日本語の資料等も多い。最も多用されているライブラリ(だと思います)。
以下はフラットファイルにInfoレベルで出力するサンプルです。
アペンダ等の設定は、通常は構成ファイルで行いますが、ここではコード上で行っています。

// add log4net.dll
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Layout;
using log4net.Repository;
using log4net.Repository.Hierarchy;

    public static class LoggerSample
    {
        static ILog _logger;

        static LoggerSample()
        {
            Hierarchy hierarchy = LogManager.GetRepository() as Hierarchy;
            ILoggerRepository repository = LogManager.GetRepository();
            log4net.Repository.Hierarchy.Logger logger = hierarchy.LoggerFactory.CreateLogger(repository, "logger");

            FileAppender appender = new FileAppender()
            {
                File = @"LogForNet.log",
                Layout = new PatternLayout(),
                AppendToFile = true,
            };
            appender.ActivateOptions();

            logger.AddAppender(appender);
            logger.Level = Level.All;

            BasicConfigurator.Configure(hierarchy, appender);

            _logger = LogManager.GetLogger("logger");

            
        }

        public static void Write(string message)
        {
            _logger.Info(message);
        }
        
    }


本家サイト

http://logging.apache.org/log4net/


posted by RR at 20:41 | Comment(0) | ログ | このブログの読者になる | 更新情報をチェックする

ログ NLog

NLog

たぶん、Log4netに次いで利用されているライブラリ。
無料で高機能で高性能でオープンソース。
以下はフラットファイルに出力するサンプル。
ロガーの設定は通常は構成ファイルで行うが、ここではコンストラクタで行っている。

本家サイト

http://nlog-project.org/

// add referance to NLog.dll
using NLog;
using NLog.Config;
using NLog.Targets;

    public static class LoggerSample
    {
        static NLog.Logger _logger;

        static LoggerSample()
        {
            var config = new LoggingConfiguration();

            var target = new FileTarget()
            {
                FileName = @"NLog.log",
                Layout = "${message}",
                KeepFileOpen = true
            };

            config.AddTarget("fileTarget", target);

            config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, target));

            LogManager.Configuration = config;

            _logger = LogManager.GetLogger("Logger");
        }

        public static void Write(string message)
        {
            _logger.Info(message);
        }
    }
posted by RR at 20:53 | Comment(0) | ログ | このブログの読者になる | 更新情報をチェックする

2015年05月10日

NLog 設定 NuGetを使って設定から出力まで

NuGet

NuGetとは.NET用のパッケージマネージャ。 VisualStudio2012からは標準採用されている。
パッケージマネージャとはライブラリのインストールや削除、依存関係の管理などをするもの。

手順

0.ログを出力するプロジェクトを用意
ログを出力するプロジェクトを先に用意しておきます。
ここではWPFのプロジェクト(画面一つにボタンが一つ配置されているもの)を使いました。

1.パッケージマネージャの起動
01_addreference.png
上図のように、ソリューションエキスプローラの参照設定を選択して右クリックで表示されるコンテクストメニューから選択します。

2.NLogを検索選択
02.pakageManager.png

ダイアログが表示されるので、左メニューから「オンライン」を選択し、右上部の検索窓で「NLog」を入力すると中央にNLog関連の候補が表示されるので「NLog」を選択して「インストール」ボタンを押下します。

3.設定完了
以上でライブラリがローカルにコピーされプロジェクトの参照にNLogが追加されています。
なお、プロジェクトにはpackages.configという設定ファイルも追加されており、中身は追加したNLogに関する設定がXML形式で記載されていました。
また、ソリューションがある実フォルダにpackagesというフォルダが生成され、こちらにはNLogのライブラリやNuGetの設定などが配置されてました。

コードサンプル

実際にログ出力してみます。
アプリケーション構成ファイルにログの設定を追記
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
  </configSections>
  <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <nlog>
    <targets>
      <target name ="logfile" type="File" filename="./Log/test.log" layout="[${longdate} ${level}]  ${message}" />
    </targets>
    <rules>
      <logger name="*" minlevel="Debug" writeTo="logfile" />
    </rules>
  </nlog>
</configuration>
画面クラスのコードビハインド側にクリックイベントハンドラを設定し、そこにログ出力コードを書いてみる。
using System.Windows;
using NLog; // ←これも必要

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            // 以下を追記
            button.Click += (_, __) =>
            {
                LogManager.GetCurrentClassLogger().Info("Button Clicked!");
            };
        }
    }
}
実行してボタンを押してみると、実行環境(bin\Debug\)にLogフォルダが生成されtest.logファイルが生成されてました。

その他

個人的には、オープンソースのライブラリに関してはソースコード自体をダウンロードしてソリューションに追加してプロジェクト参照にする方がしっくりきます。 そうしたコードを読んだりデバッグ実行で追ったりするのは勉強になりますし、不具合の解析もやりやすいですし。

ロガーの設定

設定は大きく3つ。

layout 出力フォーマットを指定する。
以下は出力日時とレベルと指定文字列を出力する設定例
 layout="[${longdate} ${level}] ${message}"

Targets ロガーの設定。ファイル出力やコンソール出力やデータベースへ出力するかといった設定。
以下はファイル出力の設定例
<targets>
<target name ="logfile" type="File" filename="./Log/test.log" layout="[${longdate} ${level}] ${message}" />
</targets>

rules どの出力レベルに対しどのターゲットを使うかの設定
以下はDebugレベル以上の指定で上設定例にあるlogfileを使用する例
<rules>
<logger name="*" minlevel="Debug" writeTo="logfile" />
</rules>


設定サンプル(ファイル肥大化抑止のため出力先を切り替え)
<target name ="logfile"
           type="File"
           filename="./Log/test.log"
           layout="[${longdate} ${level}]  ${message}"
           archiveFileName="./Log/log.{#}.backup"  // 過去分のファイル名
           archiveEvery="Day"                      // 日単位で切替る
           archiveNumbering="Rolling"              // 過去ファイルの命名付与方法
           maxArchiveFiles="7"                     // 7日分保持
/>
posted by RR at 00:03 | Comment(0) | ログ | このブログの読者になる | 更新情報をチェックする

2015年05月31日

NLog 設定項目 詳細

NLogの設定

NLogのチュートリアルやサンプルやAPI仕様などは、以下のページ(英語)にあります。
https://github.com/nlog/nlog/wiki
設定(構成)に関してはConfiguration Referenceという章に纏まっています。
ここは、そのページの抄訳になります。
誤字・誤訳・誤解釈などありましたら、本家ページでご確認してみてください。ついでにコメント頂けると参考になります。

構成ファイル

NLogの構成はXML形式のファイルで行う。

構成ファイルの配置場所

Exeアプリの場合

  • 標準のアプリケーション構成ファイル(applicationname.exe.config)
  • Exeの実行フォルダにあるapplicationname.exe.nlogファイル
  • Exeの実行フォルダにあるNLog.configファイル
  • NLogがGACとしてインスコされてない場合はNLog.dllが配置されたフォルダにNLog.dll.nlog

ASP.NETの場合

  • 標準のWeb構成ファイル(web.config)
  • web.configと同じフォルダに配置されたweb.nlog.config
  • アプリケーション実行フォルダにあるNLog.configファイル
  • NLogがGACとしてインスコされてない場合はNLog.dllが配置されたフォルダにNLog.dll.nlog

.NET Compact Framework の場合

標準のアプリケーション構成ファイルが使えないので以下となる。
  • Exeの実行フォルダにあるapplicationname.exe.nlogファイル
  • Exeの実行フォルダにあるNLog.configファイル
  • NLogがGACとしてインスコされてない場合はNLog.dllが配置されたフォルダにNLog.dll.nlog

構成ファイルの書式

NLogでは2種類の構成ファイル書式がある。
1.標準のアプリケーション構成ファイル内に記述する書式
2.別個のファイルに記述されるシンプルな書式

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

VisualStudioでインテリセンスを有効にするには以下の指定をする。
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
</nlog>
注意
・ネームスペースを使わない場合は大文字小文字の区別なし
・ネームスペースを使う場合は大文字小文字の区別あり

<nlog /> のタグがルートになり、この子要素として以下のタグで指定する。 最初の2つが必須で、それ以外は任意。

<targets /> ログのターゲット/出力を定義する
<rules /> ログのルーティング規則を定義する
<extensions /> *.dllファイルから拡張機能を読み込む
<include /> 他の構成ファイルを読み込む
<variable /> 構成ファイルの変数の値を設定する

ターゲット

<targets /> セクションにログのターゲットを定義する。以下の2つの属性を含む。
  • name:ターゲット名
  • type:ターゲット種別(ファイルとかデータベースなど)
これら2つの属性に加えて、解析やトレースに役立つようなパラメータを指定することができる。
各ターゲット毎に指定可能なパラメータは違うので詳細な仕様は本家ページを参照のこと。
また、インテリセンスもVisualStudioから入手可能である。

※ターゲットのAPI ⇒ https://github.com/nlog/nlog/wiki/Targets
※ターゲットの実装方法 ⇒ https://github.com/nlog/nlog/wiki/How%20to%20write%20a%20Target

規則

<rules /> セクションにルーティング規則を定義する。 単純なテーブル構成であり、ソースとログ名とログレベルとから成るターゲットのリストを定義する。
複数の規則が定義されている場合は、リストの順番で規則に適合するかをチェックする。
チェックに適合した場合に、その規則に定義されているターゲットでログ出力される。
規則にFinalの指定がある場合はそれ以下の規則は適用されない。

それぞれのルーティングテーブルエントリは<logger />タグの要素であり、以下の属性をもつ。
  • name:ソースまたはロガーの名前(ワイルドカード*もOK)
  • minlevel:最小ログレベル
  • maxlevel:最大ログレベル
  • level:(単数)ログレベル
  • levels:(複数)ログレベル。カンマ区切りで指定する
  • writeTo:カンマ区切りのターゲットリスト。
  • final:最後の適合となる規則。以降は適用されない。
  • enabled:enabledをdiableに指定することにより規則は適用されなくなる。
レベルに関するキーワード(level,levels,minlevel,maxlevel)の一つ以上を必ず含む必要がある。
これらは以下の順番で評価される。
1.level
2.levels
3.minlevel/maxlevel(この二つは同じ優先度)
4.キーワードなし(すべてのレベルが対象)

レイアウトとレイアウトレンダリング

NLogの最も強力な機能の一つがレイアウトを使えること。
これは${}で囲まれたタグで記述されるテキストである。
このタグはレイアウトレンダラーと呼ばれ、ログ出力に関する指定された情報を挿入するために使われる。
各所で使用され、例えば画面上に表示したりファイルに送信したりする情報を制御したり、出力先のファイル名を制御したりする。

例えば、コンソールに現在時刻・クラス名とメソッドとログレベルとメッセージとを出力するには以下のように記述する。

<target name="c" xsi:type="Console" layout="${longdate} ${callsite} ${level} ${message}" />

ファイル名自体を定義するには以下のように記述する。

<target name="f" xsi:type="File" fileName="${logger}.txt"/>

インクルードファイル

<include />セクションを使う。設定が複数のファイルに定義される場合に、他のファイルを読み込むための設定である。

<include file="${basedir}/${machinename}.config"/>

ignoreError="true"の指定をすることができる。
デフォルト値はfalseであり、明示的にtrue設定された場合は、指定ファイルがないとかフォーマットエラーであるといった例外が通知されるようになる。構成ファイル自体の不具合解析時に使う

変数

複雑だったり繰り返し使われたりするような場合に変数を定義することができる

<variable name="var" value="xxx" />

一度定義されものは ${var}により使用することができる。

自動再構成

構成ファイルに定義されている設定内容はアプリケーション起動時に自動的に読み込まれる。
WindowsServiceやWebシステムのように、プロセスが長期間稼働し続けるような場合に、アプリケーションを再起動させることなく設定を再読み込みさせるための機能。
以下の設定により、NLogが構成ファイルを監視し、変更があった場合に自動で読込を行う。

<nlog autoReload="true" />

変更監視の対処はインクルードファイルも含まれる。いづれか一つのファイルが変更された場合でも全体を再読み込みする。

トラブル解決のためのロギング

ちゃんと設定したはずにもかかわらず、ログ出力が行われない場合がある。
その原因はいろいろ想定され得るが、最も多いのが権限に起因するもの。
例えばASP.NETの場合、aspnet_wp.exe/w3wp.exeなどが物理ディスクへの書込権限を付与されていない場合など。

NLogはNLog自身が原因の場合に例外を出力しないが、以下の設定により出力させることができる。
  • < nlog throwExceptions="true" /> この設定によりNLogに起因する例外がスローされるようになる。デプロイ時などで早い不具合原因の追究が可能となる。原因判明し次第、NLog起因でのアプリケーションクラッシュを興さないようFalse設定すること。
  • < nlog internalLogFile="file.txt" /> この設定によりNLogは内部のデバッグメッセージを指定された特殊ファイルへ出力する
  • < nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" /> 内部ログレベルを指定する。ログレベルを上げるほど詳細な情報が出力される。
  • < nlog internalLogToConsole="false|true" /> 内部ログメッセージをコンソール出力するか否か
  • < internalLogToConsoleError="false|true" /> 内部ログメッセージをコンソールエラー出力するか否か

非同期プロセスとラッパーターゲット

NLogは以下のような機能を追加することにより、他のターゲットの機能をラップしたり合成したりできる。
・非同期プロセッシング(ターゲットを別のスレッドで実行させる)
・例外時のリトライ
・ロードバランシング
・バッファリング
・フィルタリング
・フェイルオーバー
構成ファイルでラッパーを定義するには、単純にターゲットノードをネストさせればよく、その階層も制限はない。
以下はリトライ機能と非同期とを付加させるサンプル。
<targets>
  <target name="n" xsi:type="AsyncWrapper">
    <target xsi:type="RetryingWrapper">
      <target xsi:type="File" fileName="${file}.txt" />
    </target>
  </target>
</targets>
非同期はよく使われるので、以下のように略記可能。
<nlog>
  <targets async="true">
    <!-- all targets in this section will automatically be asynchronous -->
  </targets>
</nlog>

デフォルトラッパー

複数のターゲットに同じラッパーを付与させる機能
<nlog>  
  <targets>  
    <default-wrapper xsi:type="AsyncWrapper">  
      <wrapper-target 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>
  <targets>
    <default-target-parameters xsi:type="File" keepFileOpen="false"/>
    <target name="f1" xsi:type="File" fileName="f1.txt"/>
    <target name="f2" xsi:type="File" fileName="f2.txt"/>
    <target name="f3" xsi:type="File" fileName="f3.txt"/>
  </targets>
</nlog>

エスケープ

設定ファイルはXML形式なので「<」「>」などは「&lt;」「&gt;」へのエスケープ処理が必要
レイアウト内では「}」のエスケープが必要。ネストされてる場合は不要
${appdomain:format={1\}{0\}}
${rot13:inner=${ndc:topFrames=3:separator=x}}

構成用のAPI

構成ファイルで定義する内容は、すべてプログラムとして記述することもできる。

使い方

NLogをコードで構成するには以下の手順が必要

1.LoggingConfigurationのインスタンスを生成して、これに構成を保持させる
2.Targetを継承する一つ以上のターゲットのインスタンスを生成
3.ターゲットのプロパティを設定
4.LoggingRuleクラスを介して規則を定義し、それをconfingurationのLoggingRulesに追加する
5.ConfigurationのインスタンスをLogManager.Configurationに設定することに有効にする

サンプル

以下は2つのターゲットを持つサンプルコード。
一つは色付きのコンソールへ、もう一方はDebug以上のレベルのログをファイル出力する
using NLog;
using NLog.Targets;
using NLog.Config;
using NLog.Win32.Targets;

class Example
{
    static void Main(string[] args)
    {
        // 1.configuration を生成 
        var config = new LoggingConfiguration();

        // 2.targetを生成し configurationに設定 
        var consoleTarget = new ColoredConsoleTarget();
        config.AddTarget("console", consoleTarget);

        var fileTarget = new FileTarget();
        config.AddTarget("file", fileTarget);

        // 3.targetのプロパティを設定
        consoleTarget.Layout = @"${date:format=HH\\:MM\\:ss} ${logger} ${message}";
        fileTarget.FileName = "${basedir}/file.txt";
        fileTarget.Layout = "${message}";

        // 4.規則を定義
        var rule1 = new LoggingRule("*", LogLevel.Debug, consoleTarget);
        config.LoggingRules.Add(rule1);

        var rule2 = new LoggingRule("*", LogLevel.Debug, fileTarget);
        config.LoggingRules.Add(rule2);

        // 5.構成を有効化
        LogManager.Configuration = config;
    }
}

API

こちらのページにクラスライブラリあります。
http://nlog-project.org/documentation/v3.2.1/html/R_Project_NLog.htm

ターゲット

使用法

ターゲットは、メッセージを表示したり、記録したり、他の宛先へ送ったりするために使用される。
2種類あり、一つはメッセージを受け取り、それを処理する。もう一つは、メッセージを振り分けたりバッファリングしたりする。後者はラッパーと呼ばれる。

提供されているターゲット

※各項目の詳細な設定についてのリンクがあります。https://github.com/nlog/nlog/wiki/Targets
  • AspNetTrace - ログメッセージを ASP.NET trace に書く
  • AspResponse - ASP Response object を介してログメッセージを出力する
  • Chainsaw - Log4JのビューワーであるChainsowのリモートインスタンスにログメッセージを送る
  • ColoredConsole - コンソールにカスタマイズした色でログメッセージを書く
  • Console - コンソールにログメッセージを書く
  • Database - ADO.NETプロバイダーを使ってデータベースにログメッセージを書く
  • Debug - モック(テスト用)
  • Debugger - アタッチされたデバッガにログメッセージを書く
  • EventLog - イベントログにログメッセージを書く
  • File - ログメッセージをファイルに書く
  • FormControl - 指定された名前のWindows.Forms.ControlのTextプロパティにロギングする
  • LogReceiverService - WCFやWeb ServicesによるNLog Receiver Serviceにログメッセージを送る
  • Mail - SMTP プロトコルを使って電子メールでログメッセージを送る
  • Memory - プログラムで取得できるように、メモリ上のArrayListにログメッセージを書く
  • MessageBox - ログメッセージをメッセージボックスを使ってポップアップ表示する
  • MethodCall - ログメッセージ毎にパラメータを付与して指定された静的メソッドを呼ぶ
  • MSMQ - MSMQで管理されている指定されたメッセージキューにログメッセージを書く
  • Network - ネットワークを介してログメッセージを送る
  • NLogViewer - リモートのNLog Viewerにログメッセージを送る
  • Null - ログメッセージを破棄する。主にデバッグとかベンチマークで使用
  • OutputDebugString - Win32 APIのOutputDebugString()でログメッセージを出力する
  • PerfCounter - 書き込み処理毎に指定されたパフォーマンスカウンタをインクリメントする
  • RichTextBox - 存在している、若しくは新規に作るRichTextBoxにログテキストをロギングする
  • Trace - System.Diagnostics.Traceにログメッセージを送る
  • WebService - ログメッセージ毎に指定されたWebServiceをコールする

ラッパーターゲット

  • AspNetBufferingWrapper - ASP.NETのリクエスト中にログイベントをバッファし、リクエスト終了時にラップされたターゲットに送る
  • AsyncWrapper - ターゲットが書き込み中は非同期でバッファリングを実行する
  • AutoFlushWrapper - ラップされたターゲットに書き込み毎にフラッシュする
  • BufferingWrapper - ログイベントをバッファし、ラップされたターゲットに纏めて送る。メールターゲットとの組み合わせで有用
  • FallbackGroup - エラー時のフェイルバック機能を提供
  • FilteringWrapper - 条件に基づきログエントリーをフィルタリングする
  • ImpersonatingWrapper - 書き込み時に他のユーザに偽装
  • PostFilteringWrapper - イベントのグループにより評価された複数の条件によりバッファされたログをフィルタリングする
  • RandomizeGroup - ランダムに選択されたターゲットにログを送る
  • RepeatingWrapper - 指定回数分それぞれおのログイベントを繰り返す
  • RetryingWrapper - 書き込み失敗したら再挑戦
  • RoundRobinGroup - ターゲットに順番にログイベントを振り分ける
  • SplitGroup - 全てのターゲットにログイベントを書く

レイアウト

レイアウトはほとんどのターゲットにある属性の一つ。
レイアウト属性はロギングされる情報のフォーマットを決めるために使われる。
多くの定義済みのマクロつまりレイアウトレンダラーがあります。

デフォルトレイアウト

ターゲットがレイアウト属性を持つ場合は、自由に指定できるが、明示的な指定がない場合は以下のものが使用される。
${longdate}|${level:uppercase=true}|${logger}|${message}

定義済レイアウト

※各レイアウトの詳細な仕様はこちらのページからリンクされています。https://github.com/nlog/nlog/wiki/Layouts
  • CsvLayout - CSVフォーマットイベント用特殊レイアウト
  • LayoutWithHeaderAndFooter - ヘッダーとフッターとをサポートする特殊レイアウト
  • Log4JXmlEventLayout - Log4jと共用可能なXMLエベント用特殊レイアウト
  • SimpleLayout - 出力時の情報で代替される箇所を埋め込まれた文字列を表す

レイアウトレンダラー

レイアウトレンダラーとは各レイアウトで使われるテンプレートマクロのこと。

レイアウトレンダラー

※各レンダラーの詳細な仕様はこちらのページにリンクあり。https://github.com/nlog/nlog/wiki/Layout-Renderers
  • ${appsetting} - アプリケーション構成の定義値
  • ${asp-application} - ASP アプリケーションの変数
  • ${aspnet-application} - ASP.NET アプリケーションの変数
  • ${aspnet-request} - ASP.NET リクエスト変数
  • ${aspnet-session} - ASP.NET セッション変数
  • ${aspnet-sessionid} - ASP.NET セッションID
  • ${aspnet-user-authtype} - ASP.NET ユーザー変数
  • ${aspnet-user-identity} - ASP.NET ユーザー変数
  • ${asp-request} - ASP リクエスト変数
  • ${asp-session} - ASP セッション変数
  • ${assembly-version} - アセンブリのバージョン
  • ${basedir} - 実行中のアプリケーションの基底ディレクトリ
  • ${callsite} - 呼び出し箇所(クラス名、メソッド名、ソース情報)
  • ${counter} - カウント値(各レイアウトレンダリグ毎にインクリメント)
  • ${date} - Current date and time.
  • ${document-uri} - Silverlightアプリケーションを干すとしているHTMLページのURI
  • ${environment} - 環境変数
  • ${event-context} - ログイベントのコンテクストデータ
  • ${exception} - 例外情報
  • ${file-contents} - 指定されたファイルの内容
  • ${gc} - ガベージコレクタについての情報
  • ${gdc} - Global Diagnostic Context item. log4net.との共用で使用
  • ${guid} - GUID(Globally-unique identifier)
  • ${identity} - スレッド情報(スレッド名と認証情報)
  • ${install-context} - インストールパラメーター (passed to InstallNLogConfig).
  • ${level} - ログレベル
  • ${literal} - 文字列
  • ${log4jxmlevent} - log4のChainsawやNLogViewerと共用可能なXML書式の情報
  • ${logger} - ロガー名
  • ${longdate} - ログ時の時間(書式は yyyy-MM-dd HH:mm:ss.mmm)
  • ${machinename} - プロセスが実行しているマシン名
  • ${mdc} - Mapped Diagnostic Context item. log4net.との共用で使用
  • ${message} - The formatted log message.
  • ${ndc} - Nested Diagnostic Context item. log4net.との共用で使用.
  • ${newline} - 改行文字
  • ${nlogdir} - NLog.dllが配置されているフォルダ名
  • ${performancecounter} - パフォーマンスカウンター
  • ${processid} - プロセスID
  • ${processinfo} - 実行中のプロセス情報
  • ${processname} - プロセス名
  • ${processtime} - プロセス時間(書式 HH:mm:ss.mmm)
  • ${qpc} - QueryPerformanceCounter()での戻り値である高精度の時間。秒変換も可能
  • ${registry} - レジストリ値
  • ${shortdate} - 日付(書式 yyyy-MM-dd)
  • ${sl-appinfo} - Silverlightアプリケーション情報
  • ${specialfolder} - 特殊フォルダ(マイドキュメントやプログラムファイルズなど)へのパス
  • ${stacktrace} - スタックトレース
  • ${tempdir} - 一時フォルダ
  • ${threadid} - カレントスレッドID
  • ${threadname} - カレントスレッド名
  • ${ticks} - 現在日時のTicks値
  • ${time} - 時間(書式 HH:mm:ss.mmm)
  • ${windows-identity} - TWI(Thread Windows identity)情報 (ユーザー名).

ラッパー レイアウトレンダラー

※各ラッパーの詳細な仕様はこちらのページにリンクあり⇒https://github.com/nlog/nlog/wiki/Layout-Renderers
  • ${cached} - キャッシング適用
  • ${filesystem-normalize} - ファイル名として使用できない文字を安全な文字に置換
  • ${json-encode} - JSON規則でエスケープ出力
  • ${lowercase} - 小文字変換
  • ${onexception} - 例外のみ出力
  • ${pad} - パディング適用
  • ${replace} - 置換
  • ${rot13} - ROT-13で暗号化されたテキストの復号化
  • ${trim-whitespace} - 空白削除
  • ${uppercase} - 大文字変換
  • ${url-encode} - URLを用いてのエンコード
  • ${when} - 指定された条件に合致する場合のみ出力
  • ${whenEmpty} - 他のレイアウトの出力結果が空白の場合に別のレイアウトを適用
  • ${xml-encode} - XML準拠への置換

カスタム レイアウトレンダラー

  • ${gelf} - GELF(Graylog Extended Log Format)への変換

レイアウトへの値の引き渡し

沢山のレンダラーが定義され提供されているが、独自実装することも可能。
そのレイアウトレンダラーに特定の値を引き渡すには、イベントに独自のプロパティをコード側で追加する。 詳しくは${event-context}を参照のこと。

フィルター

ログ出力は構成ファイルの定義でフィルタリング可能

※各フィルタの詳細な仕様はこちらのページにリンクあり⇒https://github.com/nlog/nlog/wiki/Filters

提供されているフィルター

  • when filter - 指定の条件に合致した場合

非推奨のフィルター

以下のフィルタではなくwhen filterを使うべし
  • whenContains filter - 特定の文字列が含まれる場合
  • whenEqual filter - 特定の文字列と等しい場合
  • whenNotContains filter - 特定の文字列が含まれない場合
  • whenNotEqual filter - 特定の文字列と等しくない場合

条件

when filterと一緒に使われる条件式。
Whenフィルターがアクションを起こすか否かを決定するのにつかわれる。

言語仕様

条件式は特殊なミニ言語で記述される。
  • 関係演算子 - == , != , < , <= , >= , >(エスケープが必要な文字あり)
  • ブール値演算子 - and , or , not
  • リテラル文字列 - &{somerenderer}レンダラーを使う
  • ブール値文字列 - true , false
  • 数値型文字列 - 例えば 12345はInt型文字列で1234.56は浮動小数点型文字列
  • ログレベル文字列 - LogLevel.Trace,LogLevel.Debug.....
  • 予約語文字列 - level,message,logger
  • 括弧 - 既定のプロパティとグループ式とを上書きする
  • 関数 - stringobjectとのテストを行う

関数

以下の関数が使える
  • contains(s1,s2) - 第一引数の文字列に第二引数が含まれていればtrueを、いなければfalseを返却
  • end-with(s1,s2) - 第一引数の文字列が第二引数の文字列で終わっていればtrueを、いなければfalseを返却
  • equals(o1,o2) - 二つの引数が同じ場合はtrueを、そうでなければfalseを返却
  • length(s) - 指定文字列の長さを返却
  • start-with(s1,s2) - 第一引数の文字列が第二引数の文字列で始まっていればtrueを、いなければfalseを返却

<rules>
    <logger name="*" writeTo="file">
        <filters>
            <when condition="length('${message}') > 100" action="Ignore" />
            <when condition="equals('${logger}','MyApps.SomeClass')" action="Ignore" />
            <when condition="(level >= LogLevel.Debug and contains('${message}','PleaseDontLogThis')) or level==LogLevel.Warn" action="Ignore" />
            <when condition="not starts-with('${message}','PleaseLogThis')" action="Ignore" />
        </filters>
    </logger>
</rules>

拡張

静的公開クラスに静的メソッドを定義し、以下のようにConditionMethods,ConditionMethod属性をそれぞれ付与。

namespace MyExtensionNamespace 
{ 
    using System; 
    using NLog.Conditions; 

    [ConditionMethods] 
    public static class MyConditionMethods 
    { 
        [ConditionMethod("myrandom")] 
        public static int Random(int max) 
        { 
            return new Random().Next(max); 
        } 
    } 
} 

<rules>
    <logger name="*" writeTo="file">
        <filters>
            <when condition="length('${message}') > 100" action="Ignore" />
            <when condition="equals('${logger}','MyApps.SomeClass')" action="Ignore" />
            <when condition="(level >= LogLevel.Debug and contains('${message}','PleaseDontLogThis')) or level==LogLevel.Warn" action="Ignore" />
            <when condition="not starts-with('${message}','PleaseLogThis')" action="Ignore" />
        </filters>
    </logger>
</rules>

ログレベル

以下の6種類(Log4netと同じ)
  • off
  • Fatal
  • Error
  • Warn
  • Info
  • Debug
  • Trace
posted by RR at 11:09 | Comment(0) | ログ | このブログの読者になる | 更新情報をチェックする