jq でJSON を整形

本家 Tutorial : https://stedolan.github.io/jq/tutorial/

わかりやすい紹介 : https://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af

inotify-tools の分かり易い説明 : https://qiita.com/stc1988/items/464410382f8425681c20

アプリケーションのログがJSONテキストで、フィールドを分けて、データベースのテーブルに追加できるスクリプトを作りました。
MySQL 5.7 から、JSON型が提供されたので、整形しないでそのまま追加すれば使えますが、抽出のSQLに慣れてなく、列で分けた方が視認性良いのでそうしてます。

[ 大まかな流れ ]

1) ログは逐次出力されるので、inotify で更新を待ち受け
2) ログの行が追加された時点で、発火
3) 最終行を取得して、sedとかgawkで変換
4) jqで各列値を取得
5) SQL文に整形して、INSERTコマンドを渡しテーブルに追加

[ コード例 ]


#!/bin/bash

### NextCloud log add to my table log ###

# $1 : SiteName (end part of URI) 
# required package: inotify-tools

## --------- const ------------- ##

FIELD_ARRAY=(reqId level time remoteAddr user app method url message userAgent version,)
INSSQL="INSERT INTO log_use (NM_SITE,"

INTERVAL_COMMIT=10         # 一括した時スキップするので
# in order to avoid 
# should write notify result to file. and check row count by wc. and write SQL script file

## ----------------------------- ##

nmsite=$1

watch_file=/home/ncdata/${nmsite}/nextcloud.log
#events=(-e CREATE -e MODIFY -e MOVED_TO)

cnt=0
argsql=""
cmdpost="";
while inotifywait -e MODIFY ${watch_file}; do
  row=`tail -n 1 ${watch_file}`
  echo ${row}
  echo "------------------------------------------------------------"

  # execute jq #
  #echo ${row} | jq
  
  #echo "-- method"
  #echo ${row} | jq -r '.method'
  let cnt++
  echo ${cnt}

  echo "-- SQL"
  cursql=${INSSQL}
  # Field part # 
  for fld in ${FIELD_ARRAY[@]}; do
    cursql=${cursql}${fld}","
  done
  cursql=${cursql}") VALUES ("
  cursql=`echo ${cursql} | sed 's/,,//g'`

  # Value part #
  cursql=${cursql}"'"${nmsite}"',"
  for fld in ${FIELD_ARRAY[@]}; do
    nmfld=`echo ${fld} | sed 's/,//'`
    curval=`echo ${row} | jq ."${nmfld}"`

    if [ ${nmfld} = "time" ]; then
      curval=`echo ${curval} | sed 's/\+[0-9][0-9]:[0-9][0-9]//'`
    fi

    cursql=${cursql}${curval}","
  done
  cursql=${cursql}");"
  cursql=`echo ${cursql} | sed 's/,);/);\n/g'`
  #cursql=`echo -e $cursql"\n"`
  #echo ${cursql}


  argsql=${argsql}${cursql}

  # Execute command #
  if [ ${cnt} -eq ${INTERVAL_COMMIT} ]; then
    #cmdpost=${CMD_SQL}${argsql}"'"
    echo ${argsql} > ${INSSQL_FILENAME}

    ## debug
    tmcur=`date "+%Y%m%d-%H%M%S"`
    #cp ${INSSQL_FILENAME} ${INSSQL_FILENAME}"."${tmcur}

    echo `ls -l ${INSSQL_FILENAME}`
    cmdpost=${CMD_SQL}${INSSQL_FILENAME}
    echo "-- MySQL shell command"
    #echo ${cmdpost}
    #`${cmdpost}`      ???????????? script incorrect

    # Write MySQL database #
    mysql -u???? -p????????? mytable < ${INSSQL_FILENAME}

    argsql=""
    echo "" > ${INSSQL_FILENAME}
    cnt=0
  fi


done