プリザンターでログ出力を拡張する方法

## はじめに
プリザンターの1.4.11.0からログをデータベースの`SysLogs`テーブルだけではなく、テキストファイルに出力する機能が追加されました。この追加機能を応用して、テキストファイル以外へのログ出力機能を拡張してみましょう。

## 実装をみてみる
### C#のコード側を見てみる

今回の追加機能、実はNLogで実装されています。ロガーの実装部分を見てみましょう。プリザンターのロギング機能は、`Implem.Pleasanter.Models.SysLogModel`にひとまとめで実装されています。

https://github.com/Implem/Implem.Pleasanter/blob/main/Implem.Pleasanter/Models/SysLogs/SysLogModel.cs#L31
```csharp
private static readonly Logger logger = LogManager.GetLogger("syslogs");
```
この部分が NLogロガーの定義部分です。ここを見ると`syslogs`という名前のNLogロガーが定義されていることが分かります。

このNLogロガーに対してログ出力が実装されています。では実際に出力の実装を見てみましょう。

https://github.com/Implem/Implem.Pleasanter/blob/5773a27518ba352b2201f186bc9720c625128a6d/Implem.Pleasanter/Models/SysLogs/SysLogModel.cs#L3245-L3251
```csharp
if (Parameters.SysLog.EnableLoggingToFile)
{
    logger.ForLogEvent(SysLogType != SysLogTypes.Info ? LogLevel.Error : LogLevel.Info)
        .Message("UpdateSysLog")
        .Property("syslog", ToLogModel(this))
        .Log();
}
```

https://github.com/Implem/Implem.Pleasanter/blob/5773a27518ba352b2201f186bc9720c625128a6d/Implem.Pleasanter/Models/SysLogs/SysLogModel.cs#L3371-L3377
```csharp
if (Parameters.SysLog.EnableLoggingToFile)
{
    logger.ForLogEvent(sysLogType != SysLogTypes.Info ? LogLevel.Error : LogLevel.Info)
        .Message("WriteSysLog")
        .Property("syslog", ToLogModel(this))
        .Log();
}
```

パラメータの`SysLogs`の`EnableLoggingToFile`が`true`の時のみ、ロガーが使われるようになっています。
いずれも出力されるメッセージが異なるのみで、カスタムプロパティ`syslog`に対して、プリザンター内部のログモデル`SysLogModel`がセットされています。今回は`SysLogModel`の中でこの処理が呼ばれているため、`SysLogModel`を`this`で指しています。`ToLogModel`メソッドでは渡された`SysLogModel`を`SysLogLogModel`に変換しているだけです。

https://github.com/Implem/Implem.Pleasanter/blob/5773a27518ba352b2201f186bc9720c625128a6d/Implem.Pleasanter/Models/SysLogs/SysLogModel.cs#L3555-L3600
```csharp
public static SysLogLogModel ToLogModel(SysLogModel s)
{
    return new SysLogLogModel
    {
        CreatedTime = s.StartTime,
        SysLogId = s.SysLogId,
        Ver = s.Ver,
        SysLogType = s.SysLogType.ToInt(),
        OnAzure = s.OnAzure,
        MachineName = s.MachineName,
        ServiceName = s.ServiceName,
        TenantName = s.TenantName,
        Application = s.Application,
        Class = s.Class,
        Method = s.Method,
        RequestData = s.RequestData,
        HttpMethod = s.HttpMethod,
        RequestSize = s.RequestSize,
        ResponseSize = s.ResponseSize,
        Elapsed = s.Elapsed,
        ApplicationAge = s.ApplicationAge,
        ApplicationRequestInterval = s.ApplicationRequestInterval,
        SessionAge = s.SessionAge,
        SessionRequestInterval = s.SessionRequestInterval,
        WorkingSet64 = s.WorkingSet64,
        VirtualMemorySize64 = s.VirtualMemorySize64,
        ProcessId = s.ProcessId,
        ProcessName = s.ProcessName,
        BasePriority = s.BasePriority,
        Url = s.Url,
        UrlReferer = s.UrlReferer,
        UserHostName = s.UserHostName,
        UserHostAddress = s.UserHostAddress,
        UserLanguage = s.UserLanguage,
        UserAgent = s.UserAgent,
        SessionGuid = s.SessionGuid,
        ErrMessage = s.ErrMessage,
        ErrStackTrace = s.ErrStackTrace,
        InDebug = s.InDebug,
        AssemblyVersion = s.AssemblyVersion,
        Comments = s.Comments.ToJson(),
        Creator = s.Creator.Id,
        Updator = s.Updator.Id,
        UpdatedTime = s.EndTime.Equals(0.ToDateTime()) ? s.StartTime : s.EndTime
    };
}
```

### 設定ファイルを見てみる
NLogでは実際の出力に関する設定群は外部の設定ファイルに切り出されているのが一般的です。プリザンターでも外部ファイルに設定が保持されています。それが`appsettings.json`になります。
これの中身を見てみましょう。

https://github.com/Implem/Implem.Pleasanter/blob/5773a27518ba352b2201f186bc9720c625128a6d/Implem.Pleasanter/appsettings.json
```json
{
    "type": null,
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        }
    },
    "NLog": {
        "throwConfigExceptions": true,
        "targets": {
            "async": true,
            "jsonfile": {
                "type": "File",
                "fileName": "logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/syslogs.json",
                "keepFileOpen": false,
                "concurrentWrites": true,
                "archiveFileName": "logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/syslog.{#####}.json",
                "archiveAboveSize": 10240,
                "archiveNumbering": "Sequence",
                "layout": {
                    "type": "JsonLayout",
                    "Attributes": [
                        {
                            "name": "timestamp",
                            "layout": "${date:format=O}"
                        },
                        {
                            "name": "level",
                            "layout": "${level:upperCase=true}"
                        },
                        {
                            "name": "message",
                            "layout": "${message}"
                        },
                        {
                            "name": "syslog",
                            "encode": false,
                            "layout": {
                                "type": "JsonLayout",
                                "includeEventProperties": "true"
                            }
                        },
                        {
                            "name": "exception",
                            "encode": false,
                            "layout": {
                                "type": "jsonLayout",
                                "Attributes": [
                                    {
                                        "name": "type",
                                        "layout": "${exception:format=type}"
                                    },
                                    {
                                        "name": "message",
                                        "layout": "${exception:format=message}"
                                    },
                                    {
                                        "name": "stacktrace",
                                        "layout": "${exception:format=tostring}"
                                    }
                                ]
                            }
                        }
                    ]
                }
            },
            "csvfile": {
                "type": "File",
                "fileName": "logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/syslogs.csv",
                "keepFileOpen": false,
                "concurrentWrites": true,
                "archiveFileName": "logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/syslog.{#####}.csv",
                "archiveAboveSize": 10240,
                "archiveNumbering": "Sequence",
                "layout": {
                    "type": "CSVLayout",
                    "quoting": "All",
                    "columns": [
                        {
                            "name": "timestamp",
                            "layout": "${date:format=O}"
                        },
                        {
                            "name": "level",
                            "layout": "${level:upperCase=true}"
                        },
                        {
                            "name": "message",
                            "layout": "${message}"
                        },
                        {
                            "name": "CreatedTime",
                            "layout": "${event-properties:syslog:format=o:objectpath=CreatedTime}"
                        },
                        {
                            "name": "SysLogId",
                            "layout": "${event-properties:syslog:objectpath=SysLogId}"
                        },
                        {
                            "name": "Ver",
                            "layout": "${event-properties:syslog:objectpath=Ver}"
                        },
                        {
                            "name": "SysLogType",
                            "layout": "${event-properties:syslog:objectpath=SysLogType}"
                        },
                        {
                            "name": "OnAzure",
                            "layout": "${event-properties:syslog:objectpath=OnAzure}"
                        },
                        {
                            "name": "MachineName",
                            "layout": "${event-properties:syslog:objectpath=MachineName}"
                        },
                        {
                            "name": "ServiceName",
                            "layout": "${event-properties:syslog:objectpath=ServiceName}"
                        },
                        {
                            "name": "TenantName",
                            "layout": "${event-properties:syslog:objectpath=TenantName}"
                        },
                        {
                            "name": "Application",
                            "layout": "${event-properties:syslog:objectpath=Application}"
                        },
                        {
                            "name": "Class",
                            "layout": "${event-properties:syslog:objectpath=Class}"
                        },
                        {
                            "name": "Method",
                            "layout": "${event-properties:syslog:objectpath=Method}"
                        },
                        {
                            "name": "Api",
                            "layout": "${event-properties:syslog:objectpath=Api}"
                        },
                        {
                            "name": "SiteId",
                            "layout": "${event-properties:syslog:objectpath=SiteId}"
                        },
                        {
                            "name": "ReferenceId",
                            "layout": "${event-properties:syslog:objectpath=ReferenceId}"
                        },
                        {
                            "name": "ReferenceType",
                            "layout": "${event-properties:syslog:objectpath=ReferenceType}"
                        },
                        {
                            "name": "Status",
                            "layout": "${event-properties:syslog:objectpath=Status}"
                        },
                        {
                            "name": "Description",
                            "layout": "${event-properties:syslog:objectpath=Description}"
                        },
                        {
                            "name": "RequestData",
                            "layout": "${event-properties:syslog:objectpath=RequestData}"
                        },
                        {
                            "name": "HttpMethod",
                            "layout": "${event-properties:syslog:objectpath=HttpMethod}"
                        },
                        {
                            "name": "RequestSize",
                            "layout": "${event-properties:syslog:objectpath=RequestSize}"
                        },
                        {
                            "name": "ResponseSize",
                            "layout": "${event-properties:syslog:objectpath=ResponseSize}"
                        },
                        {
                            "name": "Elapsed",
                            "layout": "${event-properties:syslog:objectpath=Elapsed}"
                        },
                        {
                            "name": "ApplicationAge",
                            "layout": "${event-properties:syslog:objectpath=ApplicationAge}"
                        },
                        {
                            "name": "ApplicationRequestInterval",
                            "layout": "${event-properties:syslog:objectpath=ApplicationRequestInterval}"
                        },
                        {
                            "name": "SessionAge",
                            "layout": "${event-properties:syslog:objectpath=SessionAge}"
                        },
                        {
                            "name": "SessionRequestInterval",
                            "layout": "${event-properties:syslog:objectpath=SessionRequestInterval}"
                        },
                        {
                            "name": "WorkingSet64",
                            "layout": "${event-properties:syslog:objectpath=WorkingSet64}"
                        },
                        {
                            "name": "VirtualMemorySize64",
                            "layout": "${event-properties:syslog:objectpath=VirtualMemorySize64}"
                        },
                        {
                            "name": "ProcessId",
                            "layout": "${event-properties:syslog:objectpath=ProcessId}"
                        },
                        {
                            "name": "ProcessName",
                            "layout": "${event-properties:syslog:objectpath=ProcessName}"
                        },
                        {
                            "name": "BasePriority",
                            "layout": "${event-properties:syslog:objectpath=BasePriority}"
                        },
                        {
                            "name": "Url",
                            "layout": "${event-properties:syslog:objectpath=Url}"
                        },
                        {
                            "name": "UrlReferer",
                            "layout": "${event-properties:syslog:objectpath=UrlReferer}"
                        },
                        {
                            "name": "UserHostName",
                            "layout": "${event-properties:syslog:objectpath=UserHostName}"
                        },
                        {
                            "name": "UserHostAddress",
                            "layout": "${event-properties:syslog:objectpath=UserHostAddress}"
                        },
                        {
                            "name": "UserLanguage",
                            "layout": "${event-properties:syslog:objectpath=UserLanguage}"
                        },
                        {
                            "name": "UserAgent",
                            "layout": "${event-properties:syslog:objectpath=UserAgent}"
                        },
                        {
                            "name": "SessionGuid",
                            "layout": "${event-properties:syslog:objectpath=SessionGuid}"
                        },
                        {
                            "name": "ErrMessage",
                            "layout": "${event-properties:syslog:objectpath=ErrMessage}",
                            "quoting": "All"
                        },
                        {
                            "name": "ErrStackTrace",
                            "layout": "${replace-newlines:replacement=|:${event-properties:syslog:objectpath=ErrStackTrace}}",
                            "quoting": "All"
                        },
                        {
                            "name": "InDebug",
                            "layout": "${event-properties:syslog:objectpath=InDebug}"
                        },
                        {
                            "name": "AssemblyVersion",
                            "layout": "${event-properties:syslog:objectpath=AssemblyVersion}"
                        },
                        {
                            "name": "Comments",
                            "layout": "${event-properties:syslog:objectpath=Comments}"
                        },
                        {
                            "name": "Creator",
                            "layout": "${event-properties:syslog:objectpath=Creator}"
                        },
                        {
                            "name": "Updator",
                            "layout": "${event-properties:syslog:objectpath=Updator}"
                        },
                        {
                            "name": "UpdatedTime",
                            "layout": "${event-properties:syslog:format=o:objectpath=UpdatedTime}"
                        },
                        {
                            "name": "exception",
                            "layout": "${replace-newlines:replacement=|:${exception:format=ToString}}",
                            "quoting": "All"
                        }
                    ]
                }
            },
            "logconsole": {
                "type": "AsyncWrapper",
                "target": {
                    "type": "Console",
                    "detectConsoleAvailable": true,
                    "writeBuffer": true
                }
            }
        },
        "rules": [
            {
                "logger": "console",
                "minLevel": "Info",
                "writeTo": "logconsole"
            },
            {
                "logger": "syslogs",
                "minLevel": "Info",
                "writeTo": "csvfile"
            }
        ]
    }
}
```

中身の解説は公式マニュアル([システムログをテキスト出力できるようにする](https://pleasanter.org/ja/manual/syslogs-text-output))にも記載があるので詳しい説明はそちらに譲ります。
ここで着目すべき点は、`layout`プロパティの`${{event-properties:syslog:objectpath=`で始まる設定値の部分です。これはさきほどの`ToSysLogModel`メソッドで生成された`SysLogLogModel`のプロパティです。 実はこれ、データベースの`SysLogs`テーブルのカラム名と1対1で対比しています。この対比しているという部分、後々出てきますので、覚えておいてください。

## 設定をしてみる
では、実際に設定してみます。NLogでは出力先(ファイルなど)のことをターゲットと言います。
このターゲットですが、NLogの公式サイトに使用可能なものが列挙されていたり([Configuration options/Targets](https://nlog-project.org/config/?tab=targets))、GitHubあたりでNLog Custom Targetなどで検索するといろいろとライブラリが出てきます。注意が必要なのは、プリザンターの1.4.x系は.NET 8で作られているので、それに互換性のあるものしか使えないということです。基本的には.NETStandard 2.0以降、または.NET Core 1.0以降や.NET 5以降に対応したものしかつかえません。ライフサイクルの都合があるので現時点では、.NETStandard 2.0や.NETStandard 2.1、.NET 8あたりに対応したものから選択するのが無難かと思います。

今回は、[NLog.Slack](https://github.com/eth0izzle/NLog.Slack)というライブラリを使ってSlackにメッセージを投げてみます。


### カスタムターゲットのDLLを配置する
カスタムターゲットのDLLを`NLog.dll`と同じ階層に格納します。マニュアル通りのセットアップだと`Implem.Pleasanter`の中です。Enterprise Editionの`License.dll`と同じところになります。
DLLの取得方法ですが、[nuget.org](https://www.nuget.org/)あたりから探してくるのが楽です。フレームワークのバージョンを指定して検索出来るからです。もちらん自分でソースコードを取得してビルドしてもOKです。
今回はnuget.orgからダウンロードしてきます。[NLog.Slack](https://www.nuget.org/packages/NLog.Slack)からパッケージをダウンロードしてきます。

拡張子が`nupkg`になっているので`zip`に変更します。
```console
>ren nlog.slack.2.0.0.nupkg nlog.slack.2.0.0.zip
```
そして、このZIPファイルを解凍して
```console
>mkdir nlog.slack.2.0.0
>tar -xf nlog.slack.2.0.0.zip -C nlog.slack.2.0.0
>tree /f nlog.slack.2.0.0
```
中身を見てみます。
```
C:\USERS\VEHICLEVISION\DOWNLOADS\NLOG.SLACK.2.0.0
│  .signature.p7s
│  NLog.Slack.nuspec
│  [Content_Types].xml
│
├─lib
│  ├─net45
│  │      NLog.Slack.dll
│  │
│  └─netstandard2.0
│          NLog.Slack.dll
│
├─package
│  └─services
│      └─metadata
│          └─core-properties
│                  51baff12b5f44b8d8b84fb5e392c9a23.psmdcp
│
└─_rels
        .rels
```
`NLog.Slack.dll`が2つあります。前述の通り、プリザンターの1.4.x系は.NET 8での実装になるので`netstandard2.0`の中のDLLを使用します。

と、ここまでは簡単なのですが次が結構大変な作業です。それは依存関係の追加です。依存関係は追加したDLLが読み出しているDLLのことで、追加したDLLが動くために必要なDLLとなります。nuget.orgだとDependenciesタブから参照することが出来ます。
今回選定した`NLog.Slack`では依存するものがないので、代わりにNLogでSyslogへ出力を使用するときによく使われる`NLog.Targets.Syslog`で見てみましょう。次の様な依存関係があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/f17a0703-b308-207c-6f3d-29ab21e2582c.png)
この例だと`Polly.Contrib.WaitAndRetry`が依存関係にあります。これに対しても前述と同じような方法でDLLを取り出して同じフォルダに格納します。依存関係にさらに依存関係がある場合はそれをさらに繰り返して、全ての依存関係を解消させる必要があります。
プリザンターが標準で持っているライブラリに対して依存関係が設定されている場合があるので、その場合は、標準で持っているライブラリのバージョンを確認して依存関係を満たすかどうかの確認が必要になります。（バージョン関係が満たせないときは、バージョンアップ方向だと上書きで対応出来る場合がありますが、そのライブラリへの依存している/されているの関係が満たせるかどうかは分からないため厳密にやるにはぷのソースコードをダウンロードしてきて、ライブラリの依存関係をnugetで調べる必要があります）

### SlackのWebhook用のURLを取得する
SlackのWebhook用のURLを取得してください。取得方法はここでは割愛します。

### SysLog.jsonの書き換え
まずは、[公式マニュアル](https://pleasanter.org/ja/manual/sys-log-json)に従って、`SysLog.json`の`EnableLoggingToFile`を`true`に書き換えます。

### appsettings.jsonの書き換え
次にappsettings.jsonを下記の様に書き換えます。
`extensions`が先ほど配置したDLLを指すところになります。`slack.layout`が出力したいものを設定する部分になります。データベースの`SysLogs`テーブルのカラムと1対1になるよというところがここで生きてきます。出力したいlayoutを`csvfile.Attributes.layout`を参考に書き上げてみてください。
また、ログの出力レベルについては、`"writeTo": "slack"`の1行上の`minLevel`で設定します。この設定ではInfo異常のレベルのものが出力される(プリザンターの現状の設定はInfoとErrorのみ)ようになりますが、Errorのみで良い場合は`"level":"Error",`となります。

細かいところの設定はNLogのWikiなどを各自参照してください。

```diff_json:appsettings.json
{
    "type": null,
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        }
    },
    "NLog": {
        "throwConfigExceptions": true,
+        "extensions": [
+            { "assemblyFile": "NLog.Slack.dll" }
+        ],
        "targets": {
            "async": true,
            "jsonfile": {
                "type": "File",
                "fileName": "logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/syslogs.json",
                "keepFileOpen": false,
                "concurrentWrites": true,
                "archiveFileName": "logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/syslog.{#####}.json",
                "archiveAboveSize": 10240,
                "archiveNumbering": "Sequence",
                "layout": {
                    "type": "JsonLayout",
                    "Attributes": [
                        {
                            "name": "timestamp",
                            "layout": "${date:format=O}"
                        },
                        {
                            "name": "level",
                            "layout": "${level:upperCase=true}"
                        },
                        {
                            "name": "message",
                            "layout": "${message}"
                        },
                        {
                            "name": "syslog",
                            "encode": false,
                            "layout": {
                                "type": "JsonLayout",
                                "includeEventProperties": "true"
                            }
                        },
                        {
                            "name": "exception",
                            "encode": false,
                            "layout": {
                                "type": "jsonLayout",
                                "Attributes": [
                                    {
                                        "name": "type",
                                        "layout": "${exception:format=type}"
                                    },
                                    {
                                        "name": "message",
                                        "layout": "${exception:format=message}"
                                    },
                                    {
                                        "name": "stacktrace",
                                        "layout": "${exception:format=tostring}"
                                    }
                                ]
                            }
                        }
                    ]
                }
            },
            "csvfile": {
                "type": "File",
                "fileName": "logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/syslogs.csv",
                "keepFileOpen": false,
                "concurrentWrites": true,
                "archiveFileName": "logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/syslog.{#####}.csv",
                "archiveAboveSize": 10240,
                "archiveNumbering": "Sequence",
                "layout": {
                    "type": "CSVLayout",
                    "quoting": "All",
                    "columns": [
                        {
                            "name": "timestamp",
                            "layout": "${date:format=O}"
                        },
                        {
                            "name": "level",
                            "layout": "${level:upperCase=true}"
                        },
                        {
                            "name": "message",
                            "layout": "${message}"
                        },
                        {
                            "name": "CreatedTime",
                            "layout": "${event-properties:syslog:format=o:objectpath=CreatedTime}"
                        },
                        {
                            "name": "SysLogId",
                            "layout": "${event-properties:syslog:objectpath=SysLogId}"
                        },
                        {
                            "name": "Ver",
                            "layout": "${event-properties:syslog:objectpath=Ver}"
                        },
                        {
                            "name": "SysLogType",
                            "layout": "${event-properties:syslog:objectpath=SysLogType}"
                        },
                        {
                            "name": "OnAzure",
                            "layout": "${event-properties:syslog:objectpath=OnAzure}"
                        },
                        {
                            "name": "MachineName",
                            "layout": "${event-properties:syslog:objectpath=MachineName}"
                        },
                        {
                            "name": "ServiceName",
                            "layout": "${event-properties:syslog:objectpath=ServiceName}"
                        },
                        {
                            "name": "TenantName",
                            "layout": "${event-properties:syslog:objectpath=TenantName}"
                        },
                        {
                            "name": "Application",
                            "layout": "${event-properties:syslog:objectpath=Application}"
                        },
                        {
                            "name": "Class",
                            "layout": "${event-properties:syslog:objectpath=Class}"
                        },
                        {
                            "name": "Method",
                            "layout": "${event-properties:syslog:objectpath=Method}"
                        },
                        {
                            "name": "Api",
                            "layout": "${event-properties:syslog:objectpath=Api}"
                        },
                        {
                            "name": "SiteId",
                            "layout": "${event-properties:syslog:objectpath=SiteId}"
                        },
                        {
                            "name": "ReferenceId",
                            "layout": "${event-properties:syslog:objectpath=ReferenceId}"
                        },
                        {
                            "name": "ReferenceType",
                            "layout": "${event-properties:syslog:objectpath=ReferenceType}"
                        },
                        {
                            "name": "Status",
                            "layout": "${event-properties:syslog:objectpath=Status}"
                        },
                        {
                            "name": "Description",
                            "layout": "${event-properties:syslog:objectpath=Description}"
                        },
                        {
                            "name": "RequestData",
                            "layout": "${event-properties:syslog:objectpath=RequestData}"
                        },
                        {
                            "name": "HttpMethod",
                            "layout": "${event-properties:syslog:objectpath=HttpMethod}"
                        },
                        {
                            "name": "RequestSize",
                            "layout": "${event-properties:syslog:objectpath=RequestSize}"
                        },
                        {
                            "name": "ResponseSize",
                            "layout": "${event-properties:syslog:objectpath=ResponseSize}"
                        },
                        {
                            "name": "Elapsed",
                            "layout": "${event-properties:syslog:objectpath=Elapsed}"
                        },
                        {
                            "name": "ApplicationAge",
                            "layout": "${event-properties:syslog:objectpath=ApplicationAge}"
                        },
                        {
                            "name": "ApplicationRequestInterval",
                            "layout": "${event-properties:syslog:objectpath=ApplicationRequestInterval}"
                        },
                        {
                            "name": "SessionAge",
                            "layout": "${event-properties:syslog:objectpath=SessionAge}"
                        },
                        {
                            "name": "SessionRequestInterval",
                            "layout": "${event-properties:syslog:objectpath=SessionRequestInterval}"
                        },
                        {
                            "name": "WorkingSet64",
                            "layout": "${event-properties:syslog:objectpath=WorkingSet64}"
                        },
                        {
                            "name": "VirtualMemorySize64",
                            "layout": "${event-properties:syslog:objectpath=VirtualMemorySize64}"
                        },
                        {
                            "name": "ProcessId",
                            "layout": "${event-properties:syslog:objectpath=ProcessId}"
                        },
                        {
                            "name": "ProcessName",
                            "layout": "${event-properties:syslog:objectpath=ProcessName}"
                        },
                        {
                            "name": "BasePriority",
                            "layout": "${event-properties:syslog:objectpath=BasePriority}"
                        },
                        {
                            "name": "Url",
                            "layout": "${event-properties:syslog:objectpath=Url}"
                        },
                        {
                            "name": "UrlReferer",
                            "layout": "${event-properties:syslog:objectpath=UrlReferer}"
                        },
                        {
                            "name": "UserHostName",
                            "layout": "${event-properties:syslog:objectpath=UserHostName}"
                        },
                        {
                            "name": "UserHostAddress",
                            "layout": "${event-properties:syslog:objectpath=UserHostAddress}"
                        },
                        {
                            "name": "UserLanguage",
                            "layout": "${event-properties:syslog:objectpath=UserLanguage}"
                        },
                        {
                            "name": "UserAgent",
                            "layout": "${event-properties:syslog:objectpath=UserAgent}"
                        },
                        {
                            "name": "SessionGuid",
                            "layout": "${event-properties:syslog:objectpath=SessionGuid}"
                        },
                        {
                            "name": "ErrMessage",
                            "layout": "${event-properties:syslog:objectpath=ErrMessage}",
                            "quoting": "All"
                        },
                        {
                            "name": "ErrStackTrace",
                            "layout": "${replace-newlines:replacement=|:${event-properties:syslog:objectpath=ErrStackTrace}}",
                            "quoting": "All"
                        },
                        {
                            "name": "InDebug",
                            "layout": "${event-properties:syslog:objectpath=InDebug}"
                        },
                        {
                            "name": "AssemblyVersion",
                            "layout": "${event-properties:syslog:objectpath=AssemblyVersion}"
                        },
                        {
                            "name": "Comments",
                            "layout": "${event-properties:syslog:objectpath=Comments}"
                        },
                        {
                            "name": "Creator",
                            "layout": "${event-properties:syslog:objectpath=Creator}"
                        },
                        {
                            "name": "Updator",
                            "layout": "${event-properties:syslog:objectpath=Updator}"
                        },
                        {
                            "name": "UpdatedTime",
                            "layout": "${event-properties:syslog:format=o:objectpath=UpdatedTime}"
                        },
                        {
                            "name": "exception",
                            "layout": "${replace-newlines:replacement=|:${exception:format=ToString}}",
                            "quoting": "All"
                        }
                    ]
                }
            },
            "logconsole": {
                "type": "AsyncWrapper",
                "target": {
                    "type": "Console",
                    "detectConsoleAvailable": true,
                    "writeBuffer": true
                }
-            }
+            },
+            "slack": {
+                "type": "Slack",
+                "layout": "${longdate}|${level}|${message} |${event-properties:syslog:objectpath=ErrMessage} |${replace-newlines:replacement=|:${event-properties:syslog:objectpath=ErrStackTrace}}",
+                "webHookUrl": "**SlackのWebhook用URL**"
+            }
        },
        "rules": [
            {
                "logger": "console",
                "minLevel": "Info",
                "writeTo": "logconsole"
            },
            {
                "logger": "syslogs",
                "minLevel": "Info",
                "writeTo": "csvfile"
-            }
+            },
+            {
+                "logger": "syslogs",
+                "minLevel": "Info",
+                "writeTo": "slack"
+            }
        ]
    }
}
```

## 動かしてみる
ここまでできたら後は動かすだけです。プリザンターのプロセスを再起動させると動き始めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/1445dcfd-0c23-3f0d-ce52-e053eded7c20.png)
Slackにプリザンターからのログが飛んでいることが確認出来ました。

## まとめ
プリザンターにNLogが組み込まれたことによって、いろいろなターゲットに対してログを投げることができるようになりました。Azureで運用している場合はApplicationInsightsに、AWSで運用している場合はCloudWatchに、はたまたエラーの時のは管理者にメールでと活用の方法は様々です。
依存関係の解消の部分や、使用している.NETバージョンの選定が難しい、NLogの設定回りもC#やVB.NETなどの.NET系の言語開発になれていないととっつきにくいなどと、いろいろと難易度が高い点がありますが、使いこなせるようになると強い武器になります。皆さんも是非試して見てください。