PowerShellでPSFrameworkのLoggingを利用してログ出力してみる

`PSFramework`は`PowerShell Gallery`に公開されているPowerShellモジュールとなっており、`Framework`と名付けられているだけあって、各種便利機能が提供されています。


>Prominent features:
>
>Advanced message & logging functionality
>Manage scripts & modules using DSC
>Simple Tab Completion
>Runspace-safe development
>PowerShell Scheduled tasks

今回はこのフレームワークに含まれているloggingの機能利用してみます。

PowerShellでスクリプトを作成する際に、ログ出力をするためのその場限りの`logger`を作成したりしますが。
こういうフレームワークを使うのも、一つの方法かと思います。

`PSFramework`のメンテナーは[Friedrich Weinmannさん](https://twitter.com/fredweinmann)。

## 各種サイト

- [PSFramework](https://www.powershellgallery.com/packages/PSFramework/)
- [PSFramework Documentation](https://psframework.org/documentation/documents/psframework.html)
- [PowerShell Framework](https://psframework.org/)
- [Logging in a DevOps world by Friedrich Weinmann](https://www.youtube.com/watch?v=Uy5Qd9g25Dg)
- [FriedrichWeinmann/P2019-PSSummit-Logging-in-a-DevOps-World](https://github.com/FriedrichWeinmann/P2019-PSSummit-Logging-in-a-DevOps-World)
- [PSConfAsia 2018: Logging in a DevOps world](https://livestream.com/gaelcolas/psconfasia/videos/182706619)

## 今回利用する環境

- Windows 21H2
- PSFramework 1.6.214

## インストール

```PowerShell
# ユーザスコープにインストールする場合
Install-Module PSFramework -Scope CurrentUser

# インストールチェック
Get-Module PSFramework -ListAvailable
```

## ログを書き込んでみる

- [PSFramework Documentation Logging](https://psframework.org/documentation/documents/psframework/logging.html)
- [Write-PSFMessage](https://psframework.org/documentation/commands/PSFramework/Write-PSFMessage.html)

`PSFramework`では`Write-PSFMessage`コマンドレットを利用してログを書込みます。

```powershell:helloworld.ps1
Write-PSFMessage -Message "HelloWorld"

Write-PSFMessage -Message "HelloWorld" -Level Verbose

Write-PSFMessage -Message "HelloWorld" -Level Host

Write-PSFMessage -Message "HelloWorld" -Level Warning

Write-PSFMessage -Message "HelloWorld" -Level Error

Write-PSFMessage -Message "HelloWorld" -Level Debug
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/d023b2aa-4c8e-c9f4-04db-c71b71377fa4.png)

## 書き込まれたログについて

[Getting Started with Logging](https://psframework.org/documentation/quickstart/psframework/logging.html)
[Logging to: Debuglog](https://psframework.org/documentation/documents/psframework/logging/loggingto/debuglog.html)

`PSFramework`では`Write-PSFMessage`でログを書き込む事がわかりましたが。
ここでは書き込まれたログがどう扱われているか確認します。

`PSFramework`ではログを`メモリ`と｀ファイルシステム（AppDataフォルダ配下のファイル）`に保持します。

### メモリ上のログを確認する　Get-PSFMessage

`PSFramework`では`Get-PSFMessage`コマンドを利用して、`Write-PSFMessage`コマンドレってで書込みしたメモリ上のログを取得します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/80295ca0-55a9-afde-1cf4-81fc47708b58.png)

### APPDATA配下のログファイルを確認する（Logging Provider:FileSystem）

[Logging Provider: FileSystem](https://psframework.org/documentation/documents/psframework/logging/providers/filesystem.html)

ログファイルは`PSFramework`のConfig `psframework.logging.filesystem.logpath` で設定された場所に出力されており。

`Get-PSFConfigValue`コマンドレットで設定値を確認できます。

```powershell
# ログファイルの保存先確認
Get-PSFConfigValue -FullName psframework.logging.filesystem.logpath
# ログファイルの保存先を開く
Get-PSFConfigValue -FullName psframework.logging.filesystem.logpath | ii
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/cf4f33be-40dd-af41-bc54-012421039a98.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/2f656a5f-82bb-7a17-498f-b706c7511e35.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/3a457e48-c419-4a82-f39e-60f33d6df34f.png)

上記のようにファイルに実行日時とメッセージが保存されています。

## Logging Provider（Logfile）

[Writing Logging Providers](https://psframework.org/documentation/documents/psframework/logging/advanced/writing-logging-providers.html)

[Logging to: A Logfile](https://psframework.org/documentation/documents/psframework/logging/loggingto/logfile.html)

`PSFramework`では書き込まれたログはデフォルトで設定されたフォルダにファイルとして保持されます。

特定の処理のログを設定したい場合は、`Logging Provider`を定義して利用します。
ここでは`Logfile`として出力する`Logginf Provider`を定義します。

```powershell
$paramSetPSFLoggingProvider = @{
    Name         = 'logfile'
    InstanceName = '<taskname>'
    FilePath     = 'C:\Logs\TaskName-%Date%.csv'
    Enabled      = $true
}
Set-PSFLoggingProvider @paramSetPSFLoggingProvider
```

上記の例では、$paramSetPSFLoggingProviderというhashテーブルを`Set-PSFLoggingProvider`に[スプラフティング](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_splatting?view=powershell-7.3)で渡して、`Logging Provider（Logfile）`を定義している。

`Logging Provider（Logfile）`を定義した後に、`Write-PSFMessage`でログに書込みを行うと、`Logging Provider（Logfile）`で定義された`FilePath`である`C:\Logs`ディレクトリに`TaskName-%Date%.csv`という形式でファイルが保存されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/5fca4ace-74b1-e61a-39c3-c4fc90b27e46.png)

## ログローテーションについて

[Log Rotation](https://psframework.org/documentation/documents/psframework/logging/loggingto/logfile.html)

先程、`c:\Logs`にログファイルを出力しましたが。
出力されたログをログローテーションしたい場合は`Logging Provider`に`LogRotatePath`を指定します。

```powershell
$paramSetPSFLoggingProvider = @{
    Name          = 'logfile'
    InstanceName  = '<taskname>'
    FilePath      = 'C:\Logs\TaskName-%Date%.csv'
    Enabled       = $true
    LogRotatePath = 'C:\Logs\TaskName-*.csv'
}
Set-PSFLoggingProvider @paramSetPSFLoggingProvider
```

このように指定する事で、`Logging Provider`が実行されるたびに`LogRetentionTime（既定値30日）`でログローテーションされるようです。

注意したいのは、ログローテーションが実行されるのは、定義した`Logging Provider`が実行されたタイミングとなるため。

`LogRetentionTime`を7日と設定しても、`Logging Provider`が30日に一度しか動かない場合は、ログローテーションが実行されるのは30日に一度となります。

## FilePathで利用できるプレースホルダについて

[Logging to: A Logfile](https://psframework.org/documentation/documents/psframework/logging/loggingto/logfile.html)

`Logging Provider`の`FilePath`で`&Date'というプレースホルダを利用していますが、利用できるプレースホルダについては上記ドキュメントに記載があります。

|Placeholder|Value|
|:-:|:-:|
|%date%|The current date in a yyyy-MM-dd format|
|%dayofweek%|The current day of the week (Monday, Tuesday, …)|
|%day%|The current day of the month|
|%hour%|The current hour of the day|
|%minute%|The current minute of the hour|
|%username%|The name of the current user, picked from environment variables.|
|%userdomain%|The domain of the user, picked from environment variables.|
|%computername%|The name of the current computer, picked from environment variables.|
|%processid%|ID of the current process|
|%logname%|The value of the setting/parameter.logname|

## 総評

本記事では`PSFramework`でとあえすログファイルとして出力する所まで説明してみました。
`Logfile`についてもcsv以外の出力形式で出力できたり。

`Logfile`な`Logging Provider`以外にも`Windows Eventlog`だったり`Splunk`などなどの`Logging Provider`が用意されており、様々な出力に対応していたり。

奥深いログ機能が提供されています。

モジュール作成者の公演動画があるので、こちらを見るのがわかり易い？

- [FriedrichWeinmann/P2019-PSSummit-Logging-in-a-DevOps-World](https://github.com/FriedrichWeinmann/P2019-PSSummit-Logging-in-a-DevOps-World)
- [PSConfAsia 2018: Logging in a DevOps world](https://livestream.com/gaelcolas/psconfasia/videos/182706619)