Tera Team でログを取るときの “タイムスタンプ” オプションみたいなことを、OS のネイティブの機能でやりたいシーンがあった。一時的な人力監視とか作業の証跡とかで。
以下、Windows の場合(PowerShell)と Linux の場合(bash)のそれぞれで。
Windows の場合(PowerShell)
ワンライナでやる
こうする。
<任意のコマンド> | foreach-object {(get-date -f "[yyyy/MM/dd HH:mm:ss.ff] ") + "$_"}
コマンドによっては表示が崩れるので、その場合は Out-String -Stream を通してやるとだいたいうまくいく。
<任意のコマンド> | out-string -stream | foreach-object {(get-date -f "[yyyy/MM/dd HH:mm:ss.ff] ") + "$_"}
結果、こうなる。
PS> ping 8.8.8.8 -t | foreach-object {(get-date -f "[yyyy/MM/dd HH:mm:ss.ff] ") + "$_"} [2015/11/02 01:04:43.31] [2015/11/02 01:04:43.32] 8.8.8.8 に ping を送信しています 32 バイトのデータ: [2015/11/02 01:04:43.32] 8.8.8.8 からの応答: バイト数 =32 時間 =7ms TTL=56 [2015/11/02 01:04:44.32] 8.8.8.8 からの応答: バイト数 =32 時間 =9ms TTL=56 [2015/11/02 01:04:45.32] 8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=56 [2015/11/02 01:04:46.32] 8.8.8.8 からの応答: バイト数 =32 時間 =12ms TTL=56
関数にする
関数にする場合は、例えばこんな感じ。
function add-timestamp { [cmdletbinding()] param ( [parameter(valuefrompipeline = $true, mandatory = $true)][psobject] $object, [string] $format = "[yyyy/MM/dd HH:mm:ss.ff] ", [switch] $trim ) process { $object | foreach-object { if ($trim) { (get-date -f $format) + "$_".trimend() } else { (get-date -f $format) + "$_" } } } }
-format(-f でもよい)で任意のフォーマットを指定できる。何も指定しなければデフォルト(”[yyyy/MM/dd HH:mm:ss.ff] “)。
-trim(-t でもよい)は、行末の不要な空白を削除するオプション。なにかの結果を format-table してから add-timestamp に渡すと、行バッファがあふれて折り返されて、全行間に空行が入って見えることがあるので、これを見掛け上抑止するためのもの。
使うときはこんな感じ。ワンライナの場合と同様、場合によっては out-string -stream を噛ませた方がよさそう。
<任意のコマンド> | add-timestamp <任意のコマンド> | add-timestamp -f "<HH:mm:ss> " <任意のコマンド> | add-timestamp -t <任意のコマンド> | out-string -stream | add-timestamp
結果、こうなる。
PS> ping 8.8.8.8 -t | add-timestamp [2015/11/02 01:16:18.65] [2015/11/02 01:16:18.65] 8.8.8.8 に ping を送信しています 32 バイトのデータ: [2015/11/02 01:16:18.66] 8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=56 [2015/11/02 01:16:19.66] 8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=56 [2015/11/02 01:16:20.66] 8.8.8.8 からの応答: バイト数 =32 時間 =5ms TTL=56 [2015/11/02 01:16:21.66] 8.8.8.8 からの応答: バイト数 =32 時間 =8ms TTL=56
Linux の場合(bash)
ワンライナでやる
こうする。
<任意のコマンド> | awk '{print strftime("[%Y/%m/%d %H:%M:%S] ") $0}'
strftime() はミリ秒単位の表示ができないっぽい。date で代替もできなそう ((やってみたら全行のタイムスタンプが同じ時刻になってダメだった))だし、しかたない。
結果、こうなる。
[kuro@localhost ~]$ vmstat 1 | awk '{print strftime("[%Y/%m/%d %H:%M:%S] ") $0}' [2015/11/01 05:04:04] procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- [2015/11/01 05:04:04] r b swpd free buff cache si so bi bo in cs us sy id wa st [2015/11/01 05:04:04] 1 0 0 483204 23324 363936 0 0 145 2 32 44 0 1 99 0 0 [2015/11/01 05:04:05] 0 0 0 483172 23324 363960 0 0 0 0 26 36 0 0 100 0 0 [2015/11/01 05:04:06] 0 0 0 483172 23324 363960 0 0 0 0 26 36 0 0 100 0 0 [2015/11/01 05:04:07] 0 0 0 483172 23324 363960 0 0 0 0 27 42 0 0 100 0 0
関数にする
関数にする場合は、例えばこんな感じ。
#!/bin/bash function add-timestamp () { f="[%Y/%m/%d %H:%M:%S] " for opt in "$@"; do case "$opt" in '-f' | '-format' ) f="$2" ;; esac done cat - | awk "{print strftime(\"$f\") \$0}" }
-format(-f でもよい)で任意のフォーマットを指定できる。何も指定しなければデフォルト(”[%Y/%m/%d %I:%M:%S] “)。
こうやってつかう。
<任意のコマンド> | add-timestamp <任意のコマンド> | add-timestamp -f "<%I:%M:%S> "
結果、こうなる。
[kuro@localhost ~]$ vmstat 1 | add-timestamp [2015/11/01 05:18:48] procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- [2015/11/01 05:18:48] r b swpd free buff cache si so bi bo in cs us sy id wa st [2015/11/01 05:18:48] 2 0 0 482800 23648 364060 0 0 110 2 30 42 0 0 99 0 0 [2015/11/01 05:18:49] 0 0 0 482768 23648 364060 0 0 0 0 33 46 0 1 99 0 0 [2015/11/01 05:18:50] 0 0 0 482768 23648 364060 0 0 0 0 27 38 0 0 100 0 0 [2015/11/01 05:18:51] 0 0 0 482768 23648 364060 0 0 0 0 23 37 0 0 100 0 0
どうにかしてミリ秒出せないかな、これ。