PowerShellのロガーを作ってみた

# はじめに
powershellを触っていてロガーがほしくなったので作ってみました。
ネットを探すとロガーはいくつか出てくる（[これ1][]・[これ2][]）し、基本的にそれを使えばいいんだけど自分好みに作りたい&勉強もかねて作成してみることに。
[これ1]:https://qiita.com/miyamiya/items/f36ce9c4b0ffea26afe0
[これ2]:https://qiita.com/asterisk9101/items/d13bf7bdd87a14ccbcaf

# やりたいこと

- コンソールとファイルへの同時出力
- コンソールへの出力は指定した文字のみを出力
- ファイルへの出力には特定の書式(年月日をつけるとか)＋指定した文字で出力
- ログレベルを指定してDebugログは開発時以外では出ないようにとかしたい
- 変数の出力とかも簡単にできたら嬉しい
 

``` powershell:こんな感じで使いたい
# ログレベルをInfoで設定したとして
$logger.Info("ほげほげ")
# =>consol:ほげほげ　file:yyyy/mm/dd hh:mm:ss [Info] ほげほげ
$logger.Debug("ふがふが")
# =>consol:出力なし　file:出力なし

# こんなのもできたら嬉しい
# ログレベルがDebugとして
$a = Get-ChildItem
$logger.Debug($a)
# =>consol:Get-ChildItemの結果　file:yyyy/mm/dd hh:mm:ss [Debug]Get-ChildItemの結果
```

# 実装結果・使い方

やりたいことはほぼほぼできた感じ。
ログレベルはError,Warn,Info,Debugの4段階で作成。

```powershell:使い方1
# ロガーの取得
$logger = Get-Logger -logLevel Info -logFilePath hoge.log

#ログ出力
$logger.Error("エラー！")
# =>consol:エラー！
# =>hoge.log:2019/04/03 00:29:01.450 [Error] エラー！

$logger.Warn("警告！")
# =>consol:警告！ 
# =>hoge.log:2019/04/03 00:29:01.465 [Warn] 警告！

$logger.Info("インフォメーション")
# =>consol:インフォメーション 
# =>hoge.log:00:29:01.465 [Info] インフォメーション

$logger.Debug("出ない・・・")
# =>consol:(出力なし) 
# =>hoge.log:(出力なし)
```

変数の出力も一応できる

```
Get-ChildItem
# Mode                LastWriteTime         Length Name
# ----                -------------         ------ ----
# -a----       2019/04/03      0:29            132 hoge.log

$logger2 = Get-Logger -logLevel Debug -logFilePath huga.log
$a = Get-ChiledItem
$logger2.Debug($a)
# =>consol:hoge.log 
# =>huga.log:2019/04/03 00:29:01.490 [Debug] hoge.log
```

コンソールには出さないスイッチも付けてみた。

```powershell:使い方2
$logger3 = Get-Logger -logLevel Info -logFilePath hunga.txt -NoDisplay
$logger3.Info("コンソールには出力しない")
# =>consol:(出力なし) 
# =>hunga.log:2019/04/03 00:29:01.503 [Info] コンソールには出力しない
```




# 実装

``` powershell:logger.ps1
$source = "public enum LogLevel{Error=0, Warn=1, Info=2, Debug=3}"
Add-Type -Language CSharp -TypeDefinition $source 

function Get-Logger
{
    Param(
        [Parameter(Mandatory)]
        [String] $logFilePath,

        [Parameter(Mandatory)]
        [LogLevel] $logLevel,

        [Switch] $NoDisplay

    )

    $loggerObj = New-Object psobject 
    
    #メンバ変数の追加
    $loggerObj | Add-Member -MemberType NoteProperty -Name logFilePath -Value $logFilePath
    $loggerObj | Add-Member -MemberType NoteProperty -Name logLevel -Value $logLevel

    #メソッドの追加
    #画面表示用スクリプト
    $outHostScript = {
        Param( 
            [Parameter(Mandatory)] [string] $logStr
        )
        Write-Host $logStr
    }
    $loggerObj | Add-Member -MemberType ScriptMethod -Name OutHost -Value $outHostScript 

    #ファイル出力用スクリプト
    $outFileScript ={
        Param( 
            [Parameter(Mandatory)] [string] $logStr,
            [Parameter(Mandatory)] [LogLevel] $level
        )
        $logStr = (Get-Date).ToString("yyyy/MM/dd HH:mm:ss.fff") + " [$($level)] $logStr"
        $logStr | Out-File -FilePath $this.logFilePath -Append -Encoding default 
    }
    $loggerObj | Add-Member -MemberType ScriptMethod -Name OutFile -Value $outFileScript 

    #ログ出力用スクリプト
    $script = {
        Param( 
            [Parameter(Mandatory)] [System.Object[]] $logStrArray
        )

        if($this.logLevel -ge $Script:level)
        {
            foreach($log in $logStrArray ){
                if( -Not($NoDisplay)){
                    $this.OutHost($log)
                }
                $this.OutFile($log, $Script:level)
            }
        }
    }
    #logLevel分メソッド作成
    foreach($level_tmep in ([System.Enum]::GetNames([LogLevel])))
    {
        [LogLevel] $level = $level_tmep
        $loggerObj | Add-Member -MemberType ScriptMethod -Name $level.toString() -Value $script.GetNewClosure()
    }

    return $loggerObj 
}

```

#解説
気が向いたら書きます。