Log filesの構文解析をPowershellで簡易にやってみる


はじめに

会社でログファイルを解析していてPowershellで簡易に出来たので共有します。

何が出来るの?

Plain Textのログファイルを構文解析して、JSONとかCSVとかHTMLとか、良い感じの形式にExportが出来ます。
その後の二次加工はExcelでも何でも好きな解析ツールに入れてね。

今回のコードのこだわりは、正規表現の中を切り替えるだけでいろんな形式のログに対応出来ることです。
下記のコードはサンプル残します。 (暇があったら自分用に増やします。)

  • Apache access_log
  • Squid access_log

前提条件

  • Powershellが読めること。
  • Windows環境が在ること。(テストとかはPowershell 5.1でやってます)
  • 正規表現が読めること。

一応環境は、Powershell 5.1だけど、Windows 7とかの Powershell 2.0でも出来るんじゃ無いかな?

コード

ざっくりと、下のコードで動きます。 必要箇所は書き換えてください。
(Apache access_logをJSON形式に変換)

Get-Content 'access_log' -Encoding utf8 | 
%{ $_ -match '^(?<remoteHost>[\w\.\-]+)\s(?<clientId>(?:-|[\w\.\-]+))\s(?<authenticateUser>(?:-|[\w\.\-]+))\s\[(?<time>[^\]]+)\]\s+"(?<requestUrl>[^"]+)"\s(?<status>\d{3})\s(?<responseSize>(?:-|\d+))(?:\s+"(?<referer>[^"]+)"\s+"(?<userAgent>[^"]+)")?$'} | 
%{ New-Object PSObject -Property $Matches} | 
Select-Object * -Exclude 0 | 
ConvertTo-JSON | 
Add-Content 'access_log.json' -Encoding utf8

注意点

解析に正規表現を用いているので、アンマッチの情報は無視されます。
-notmatch で検出するなど、情報落ちが無いように注意してください。

何やっているの?

簡単に解説します。

1行目

Get-Content 'access_log' -Encoding utf8

ファイルを読み込んでいるだけです。
-Encodingとか、-Headとか、-Tailとか、良い感じのオプションを付けて読み出してあげてください。
Reference Get-Content

2行目

%{ $_ -match '^(?<remoteHost>[\w\.\-]+)\s(?<clientId>(?:-|[\w\.\-]+))\s(?<authenticateUser>(?:-|[\w\.\-]+))\s\[(?<time>[^\]]+)\]\s+"(?<requestUrl>[^"]+)"\s(?<status>\d{3})\s(?<responseSize>(?:-|\d+))(?:\s+"(?<referer>[^"]+)"\s+"(?<userAgent>[^"]+)")?$'}

こだわりポイント。
正規表現の中に名前付き部分式を使うことで、一致した場所に可読性のある名前を付けています。

(?<name>subexpression)

Reference Named Matched Subexpression

普通に正規表現を使うと、後方参照は 1 とか 2 といった数値で作られて、別途名前との対応表が必要になりますが、これを正規表現の中に組み込むことにより、パイプ内に名前付きで放り込んでいます。

ちなみに、コード中の名前付き部分式は下記の通りです。

(?<remoteHost>[\w\.\-]+)
(?<clientId>(?:-|[\w\.\-]+))
(?<authenticateUser>(?:-|[\w\.\-]+))
(?<time>[^\]]+)
(?<requestUrl>[^"]+)
(?<status>\d{3})
(?<responseSize>(?:-|\d+))
(?<referer>[^"]+)
(?<userAgent>[^"]+)

また、普通にグループ化を行いたい部分では、後方参照が勝手に作られるのを防ぐために非キャプチャ グループを用いています。

(?:subexpression) 

Reference Noncapturing Group

3行目

%{ New-Object PSObject -Property $Matches}

$MatchesPSObjectに変換しています。
それだけ。

Reference New-Object PSObject –Property [HashTable]

4行目

Select-Object * -Exclude 0

Match すると自動で作られる、一致全文をあらわす $Matches[0] を消しています。
後で使う場合は、残して置いても良いんじゃないでしょうか? このあたりは好みです。

Reference Select-Object

5行目

ConvertTo-JSON

JSON形式に変換しています。
よく使うコマンドレットをまとめておきます。

Cmdlet メモ
ConvertTo-Json
ConvertTo-CSV -NoTypeInformation オプションを付けないと余計な型情報が入ります。
Out-GridView 画面に表示します。

6行目

Add-Content 'access_log.json' -Encoding utf8

データを保存しています。
Reference Add-Content

ログファイル用サンプル

Apache access_log

対応する形式

LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined

スクリプト

%{ $_ -match '^(?<remoteHost>[\w\.\-]+)\s(?<clientId>(?:-|[\w\.\-]+))\s(?<authenticateUser>(?:-|[\w\.\-]+))\s\[(?<time>[^\]]+)\]\s+"(?<requestUrl>[^"]+)"\s(?<status>\d{3})\s(?<responseSize>(?:-|\d+))(?:\s+"(?<referer>[^"]+)"\s+"(?<userAgent>[^"]+)")?$'}

パラメーター

Param 書式指定子 意味
remoteHost %h 接続元HostのIP,DNS
clientId %l クライアントID(ほとんど使われません)
authenticateUser %u 認証ユーザー(ほとんど使われません)
time %t アクセス時間
requestUrl %r URL情報
status %s ステータスコード
responseSize %b レスポンスサイズ
referer %{Referer}i リファラー情報(Combined Log Format)
userAgent %{User-agent}i UserAgent(Combined Log Format)

Reference Apache HTTP サーバ バージョン 2.0 ログファイル

Squid access_log

対応する形式

logformat squid      %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %[un %Sh/%<a %mt

スクリプト

%{ $_ -match '^(?<unixtime>\d+\.\d+)\s+(?<responseTime>\d+)\s(?<sourceIp>[\d\.]+)\s(?<requestStatus>\w+)/(?<statusCode>\d{3})\s(?<totalSize>\d+)\s(?<requestMethod>\w+)\s(?<requestUrl>[\w\-:/\.\?\+$]+)\s(?<userName>(?:-|[\w\.\-]+))\s(?<hierarchy>\w+)/(?<serverIP>(?:-|[\w\.\-]+))\s(?<mime>[\w\-]+/[\w\-]+)$'}

パラメーター

Param 書式指定子 意味
unixtime %ts.%tu 接続時間(UnixTime)
responseTime %tr レスポンスタイム
sourceIp %>a クライアントソースIP
requestStatus %Ss リクエストステータス(TCP_MISS etc)
statusCode %>Hs HTTPステータスコード
totalSize %<st トータルサイズ
requestMethod %rm リクエストメソッド(GET/POST etc)
requestUrl %ru リクエストURL
userName %un ユーザー名
hierarchy %Sh Squid hierarchy status(DEFAULT_PARENT etc)
serverIP %<a サーバーIP
mime %mt MIME

Reference Squid configuration directive logformat