AWKでログを監視するTips【AWKでぬるぽガッする】

# 要約

- ログの統計情報を出したりShellとの連携を図るにはAWKは便利。
- AWKみたいな文法でメトリクスが作れる[mtail](https://github.com/google/mtail
)というものがある。


# はじめに

近年、多様なシステム監視手段がありますが、既製品で満足しない場合、そこへエクスポートする前処理が結構大変なわけです。

特に、ログを常時監視して、パース、状態更新するなんて言うのはなかなか面倒なわけです。

そういった用途にAWKは結構向いていると思いました。

AWKに親しみがある方なら手っ取り早くそれっぽいものを作れるよっ！と思い記事にした次第です。

たとえば、

- 柔軟性と強力なパターンマッチング
正規表現＋組み込み変数の条件式etc..と、とてつもなく柔軟にかける＋そのまま実行できる

- 簡潔なコード
AWKは非常に簡潔だが基本は抑えてある言語仕様。
困ったらシェルに投げることもできる。

**メトリクス用途かつコマンド蹴っ飛ばしたりする必要がなければ、AWK風の構文でテキストからメトリクスを作れるmtailがおすすめです。**

https://github.com/google/mtail

# たとえばこんな風に

## ダミーログ生成

すごく適当に作ったよくわからない文字列を永遠出し続けるスクリプト

以下の2点を目標にスクリプトを書いていく

- `_its_target_([0-9]+)_([0-9]+)_(id-[0-9]+)`をawkでひっかけて任意の形式で出力する
- 「ぬるぽ」は「ガッ」する

~~~
$ bash test.sh
_its_target_6_8_id-0000000002
   ∧＿∧
（　´∀｀）＜　ぬるぽ
_its_target_7_5_id-0000000001
_its_target_2_9_id-0000000008
_its_target_9_9_id-0000000005
_its_target_8_1_id-0000000006
   ∧＿∧
（　´∀｀）＜　ぬるぽ
_its_target_6_1_id-0000000009
...etc...
~~~

https://gist.github.com/matsu2254/cca5c9336acfae8d5d59dcd871cf0d11


### AI先生曰く

このスクリプトは、Bashシェルスクリプトで書かれており、以下の機能が含まれています。

1. `print_id` 関数: ランダムなIDを生成して出力する関数です。`$1` に指定された数以下のランダムな数を使用して、3つの異なる形式のIDを生成します。

2. `random_print` 関数: ランダムな条件に基づいて、特定の条件を満たす場合にテキストアートを表示します。条件は、0から8までのランダムな数字に対して3より小さい場合です。その場合、ぬるぽというテキストアートが表示されます。

3. メインのループ: `while [ 0 ];do` を使用して、無限ループを作成しています。その中で、`print_id` と `random_print` を実行し、1秒間のスリープを挟んで繰り返します。

スクリプトは主にランダムなIDの生成と、一定の確率でテキストアートを表示する動作をしています。無限ループ内でこれらの操作が繰り返されます。

実行すると、IDが表示され、確率に基づいてぬるぽのテキストアートが表示されます。ログやシミュレーションのテスト用途に使えるかもしれません。


## 本題のAWK


`match(text_field,/__pattern__/,arry){} `
or 
`/__pattern__/{}`

でマッチした行の処理をする。

行っているのは、

**正規表現の第三グループをキーとしたマップを作成し、第一グループをバリューとする。バリューに更新があった時だけ値を書き出す。**
という処理と
**ぬるぽガッしてコマンドを実行する**
処理の二つ。

二つを合わせると？？？可能性は無限じゃね？？？

**要点**

- ファイルの書き込みは `>> ${書き込み先}`
- コマンドの実行は2パターンある
- 開いたら閉じる（コマンド・ファイル）


https://gist.github.com/matsu2254/53d7cbe4417a83a74992370869792f78

### AI先生曰く

このAWKスクリプトは、与えられた条件に基づいてログ行を処理し、ファイルにデータを書き込む機能が含まれています。以下に各部分の機能と説明を示します。

1. **`write_file` 関数:**
   - `map` と `filename` を引数として受け取り、指定されたファイルに対してヘッダー行とマップ内のデータを書き込む関数です。

2. **IDのマッチングとファイル書き込み:**
   - `match` 関数を使用して、特定のパターンにマッチする行を処理します。指定されたパターンからIDを抽出し、`MapOfTarget` と比較して更新があればファイルに書き込みます。また、更新があった場合には更新されたIDの情報を表示します。

3. **コマンドの実行:**
   - `/ぬるぽ/` というパターンにマッチした場合、`system` 関数を使用してコマンドを実行します。さらに、`getline` を使用してコマンドの実行結果を変数に代入し、それを表示します。コマンドの実行結果は `v` という変数に格納され、その後 `print` 文で表示されます。

4. **BEGIN ブロック:**
   - 最初に実行され、初期化のための処理が行われます。ここでは `TN`と `FILE_NAME` を初期化しています。

5. **END ブロック:**
   - 最後に実行され、終了時の処理が行われます。ここではファイルの削除を行っています。

スクリプト全体としては、ログの行を条件に基づいて処理し、特定の条件が満たされた場合にファイルに書き込むなど、柔軟で実用的なログ処理を行うための機能が含まれています。

---

## 実行



~~~bash
# trapは'Ctrl+c'されてもENDブロック処理したいため
$ bash test.sh  | (trap ''  INT; awk -f test.awk )
Update ID first: 9, Second: 2, third: id-0000000009
_its_target_9_2_id-0000000009
Update ID first: 3, Second: 3, third: id-0000000004
_its_target_3_3_id-0000000004
   ∧＿∧
（　´∀｀）＜　ぬるぽ
ガッ
ガッ！！ コマンド実行結果: test-Standard-PC-Q35-ICH9-2009!!!
...etc...
~~~

たったこれだけで、一応表示やりたいことはできている。
パターンマッチを複雑にしたりだとか、出力形式を蛙だとか…
コマンドやAWK実装で、複雑な処理をするとか…これに関しては、次の処理をするプログラムで行った方がよいかもしれない。

この例だと、出力ファイルはこんな具合にCSVになっている。
**同じ要領で、簡易なJSONでもPrometheusメトリクスでもつくれるのでは？？**と

~~~bash
$ cat foobar.csv
target_key,id
id-0000000008,6
id-0000000001,6
id-0000000002,1
~~~

# 参考

https://www.tohoho-web.com/ex/awk.html#redirect

http://aoki2.si.gunma-u.ac.jp/Hanasi/Algo/letsawk/getline.html

https://prometheus.io/docs/instrumenting/writing_exporters/