VBScriptで自作のログ出力関数をつくってみた

# はじめに
ZOZOTOWNではリプレイスが進められていますが、現在もVBScript（クラシックASP）で動いている機能があります。VBScriptには良い感じのログ出力機能が標準では備わっていないため、簡易的ではありますがログ出力用の処理を実装したので紹介します。

# 目次
- なぜ必要なのか？
- ログ出力処理
- 使ってみる
- まとめ

# なぜ必要なのか？
開発時のVBScriptのデバッグはVisual Studioを利用することで可能です。
ただし起動しているプロセスにアタッチしてデバッグする必要があるため、多少なりとも煩わしさがありました。そのため簡易的にな確認は`Response.write`することで値を確認することがよくありました。`Response.write`すると画面上に値が表示されるため機能によっては確認しづらい場合もありました。
そのため非常に古典的ではありますが、ログファイルに出力することでその辺の煩わしさと手間を少しでも軽減できればと思い作ってみました。

# ログ出力処理
本ログ出力処理の実装内容は非常に簡単で、ログファイルを作成し下記情報を出力しています。

- 実行日時
- ファイル名
- メソッド名
- メッセージ
- SessinID
- Gookie情報
- リクエストクエリーストリング情報

```VBScript:Logger.inc
Dim singletonLogging

Public Function Logging()
	If IsEmpty(singletonLogging) Then
		Set singletonLogging = New logger
	end if
	set Logging = singletonLogging
End Function

Class Logger
	private objLogFile

	Public Property get ENABLE_DETEIL_INFO
		ENABLE_DETEIL_INFO = true
	End Property

	Private Sub Class_Initialize()
		Dim strLogFile, objFSO
		strLogFile = "C:\work\log\log.json"

		Set objFSO = CreateObject("Scripting.FileSystemObject")

		If objFSO.FileExists(strLogFile) Then
			' ファイルオープン
			Set objLogFile = objFSO.OpenTextFile(strLogFile, 8)

		Else
			Set objLogFile = objFSO.CreateTextFile(strLogFile)

		End If

	End Sub

	Private Sub Class_Terminate()
		' ファイルクローズ
		objLogFile.Close
	End Sub

	Public Sub EMERGENCY(ByVal file, ByVal method, ByVal msg)
		log "EMERGENCY", file, method, msg
	End Sub

	Public Sub ALERT(ByVal file, ByVal method, ByVal msg)
		log "ALERT", file, method, msg
	End Sub

	Public Sub CRITICAL(ByVal file, ByVal method, ByVal msg)
		log "CRITICAL", file, method, msg
	End Sub

	Public Sub ERROR(ByVal file, ByVal method, ByVal msg)
		log "ERROR", file, method, msg
	End Sub

	Public Sub WARNING(ByVal file, ByVal method, ByVal msg)
		log "WARNING", file, method, msg
	End Sub

	Public Sub NOTICE(ByVal file, ByVal method, ByVal msg)
		log "NOTICE", file, method, msg
	End Sub

	Public Sub INFO(ByVal file, ByVal method, ByVal msg)
		log "INFO", file, method, msg
	End Sub

	Public Sub DEBUG(ByVal file, ByVal method, ByVal msg)
		log "DEBUG", file, method, msg
	End Sub
	Public Sub DEBUG_(ByVal msg)
		log "DEBUG", "", "", msg ' 簡易デバッグ用
	End Sub

    ' Dictionary型
	Public Sub DEBUG_DIC(ByVal file, ByVal method, ByVal msg, ByVal dic)
		If TypeName(dic) = "Dictionary" then
			dim keys: keys = dic.Keys()
			dim massages
			for i=0 to dic.Count-1
				massages = massages & keys(i) & "=" & dic.Item(keys(i)) & ", "
			next
			log "DEBUG", file, method, msg & ": [" & massages & "]"
		else
			log "DEBUG", file, method, "Not Data Type:" & TypeName(dic)
		end if
	End Sub


	Private Sub log(ByVal level, ByVal file, ByVal method, ByVal msg)		
		If ENABLE_DETEIL_INFO Then
			objLogFile.WriteLine _
			"{""level"":""" & level & """, ""datetime"":""" & now() & """, ""file"":""" & file & """, ""method"":""" & method & """, ""msg"":""" & msg & """," _
			& """SessionId"":""" & Session.SessionID & """," _
			& """Cookies"":""" & Request.Cookies & """," _
			& """QueryString"":""" & Request.QueryString & """}" 
		Else
			objLogFile.WriteLine _
			"{""level"":""" & level & """, ""datetime"":""" & now() & """, ""file"":""" & file & """, ""method"":""" & method & """, ""msg"":""" & msg & """}" 
		End If
	End Sub
End Class
```

# 使ってみる
使い方は非常に単純で、ログレベルに応じて関数（下記はINFOの例）を呼び分け、第一引数にファイル名、第二引数にメソッド、第三引数に任意の文字列を渡します。

```
' ログ出力処理
Logging.INFO "test.asp", "test()", "sample"
```

JSON形式で出力されたログ
```
{
  "level": "INFO",
  "datetime": "2023/12/19 9:17:57",
  "file": "test.asp",
  "method": "test()",
  "msg": "sample",
  "SessionId": "1074190475",
  "Cookies": "xxx",
  "QueryString": "xxx"
}
```

# まとめ
レガシーなVBScriptの開発ならでは事情でログ出力関数を実施してみました。
使う機会はほぼ無いと思いますが、もし機会があればご利用ください。