자바스크립트를 활성화 해주세요

p064 Powershell Closure와 Class로 작성해본 Logger

 ·  ☕ 2 min read

ScriptBlock에는 GetNewClosure라는 재미있는 함수가 있습니다. 이 함수를 사용하면 정말 Closure처럼 사용할 수 있는 객체가 리턴됩니다. 펄에서 처럼 & 문자를 사용해서 실행합니다.

closure

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<#
.SYNOPSIS
  store logging messages and write out to the file
.DESCRIPTION
  Provide logging method
.EXAMPLE
  $logger = Logger -Name <filename>
  To log messages:
  & logger -Messages "12345", "45678", "abcde"

  # accept values from pipeline
  echo "123", "456", "789" | & $logger
.EXAMPLE
  $logger = Logger -Name <filename> -Path c:\dc
  To write output to the file:
  & $logger -Flush
#>

function New-Logger {
  [CmdletBinding()]
  Param(
    [Parameter(Position = 0)]
    [String] $Path = "C:\log"
  )

  $buffer = [System.Text.StringBuilder]::new()

  $f = {
    [CmdletBinding(DefaultParameterSetName = 'Argument')]
    Param(
      [Parameter(Mandatory = $true, ParameterSetName = 'Argument', Position = 0)]
      [Parameter(Mandatory = $true, ParameterSetName = 'Pipeline', ValueFromPipeline = $true, Position = 0)]
      [Parameter(Mandatory = $false, ParameterSetName = 'Flush')]
      [Object[]] $Messages,

      [Parameter(ParameterSetName = 'Flush')]
      [String] $Name = "log",

      [Parameter(ParameterSetName = 'Flush')]
      [Switch] $Flush
    )

    Process {
      if ($Messages) {
        $Messages | ForEach-Object {
          Write-Debug "$_"
          [void]$script:buffer.AppendLine($_)
        }
      }

      if ($Name) {
        $script:name = $Name
      }

      if ($Flush) {
        $sLogPath = $Path
        $sLogName = "$Name.txt"
        $sLogFile = Join-Path -Path $sLogPath -ChildPath $sLogName
        $buffer.ToString() | Out-File -FilePath $sLogFile -Encoding utf8 -Append
      }
    }
  }.GetNewClosure()

  $f
}

개인적인 소감은

  • 간결해서 쓸만하다고 생각합니다.
  • 이런 방식으로 사용하는 것에 팀원들이 거부감을 느끼지 않는다면 말이죠.
  • 마치 perl의 문법을 사용하고 있는 듯한 느낌도 들었습니다.
  • VSCode나 IDE에서 intellisense에 문제가 없는 지 확인해야 합니다.

class

class Logger {
  [string] $Path
  hidden [System.Text.StringBuilder] $buffer

  hidden [void] Logging([string] $LogString) {
    $this.buffer.AppendLine($LogString)
  }

  [void] Debug ([string] $LogString) {
    Write-Debug "$LogString"
    $this.Logging("[DEBUG] $LogString")
  }

  [void] Error ([string] $LogString) {
    # do something, like send messages to chatwork
    $this.Logging("[ERROR] $LogString")
  }

  [void] Flush ([string] $Name) {
    $sLogFile = Join-Path -Path $this.Path -ChildPath "$Name.txt"
    $this.buffer.ToString() | Out-File -FilePath $sLogFile -Encoding utf8 -Append
  }

  Logger ([string] $Path) {
    $this.Path = $Path
    $this.buffer = [System.Text.StringBuilder]::new()
  }

  Logger () {
    $this.Path = "C:\log"
    $this.buffer = [System.Text.StringBuilder]::new()
  }
}

개인적인 소감은

  • OOP적인 느낌입니다
  • Closure보다는 좀 Verbose합니다.
  • 조금 Closure보다는 알기 쉽습니다. 버그가 있다면 잡을 때 시간이 덜 걸릴 것입니다.
  • 역시 VSCode나 IDE에서 intellisense에 문제가 없는 지 확인해야 합니다.

결론

특정상황에 좀 더 유리한 것이 있겠지만, 양쪽 다 좋습니다.

ref

공유하기

tkim
글쓴이
tkim
Software Engineer