質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

json形式のデータで、型をチェックする方法

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 5,021

score 49

前提・実現したいこと

現在、AWS S3から取得されるjson形式のデータの一部で、
StringではなくArray型になっているため、
スクリプトの処理がエラーになっているようです。
※cronで定期的にデータ取得をさせているのですが、エラーになっているデータがいまだに見つかっていない為、サンプルがありません...
※エラーメッセージの内容に関しては、別の質問(https://teratail.com/questions/28988)で質問させていただいており、回答をいただきました。

手動でデータをチェックして、削除・修正していられない(そもそもファイルが多くて見つかっていない)ので、
スクリプトで型をチェックして、処理をできないかと考えています。

json形式のデータで、型をチェックする方法はあるのでしょうか。

発生している問題・エラーメッセージ

jq: error: Cannot iterate over string 
jq: error: string and array cannot be sorted, as they are not both arrays 
~~~
eventTime の部分でソートしようとしているので、eventTimeにArray型のデータが混ざっているのではないかと考えています。

ソースコード

find /var/log/trail-log/ -name "*.json.gz" | sort | xargs gunzip -c | /usr/bin/jq '.[] | sort_by(.eventTime) | .[]' | /usr/bin/jq '{awsRegion, eventName, eventTime, userName: .userIdentity.userName, requestParameters}' | /usr/bin/jq '"[\(.eventTime)] \(.awsRegion) \(.userName) \(.eventName) \(.requestParameters)"' > trail.log

補足情報(言語/FW/ツール等のバージョンなど)

※cronで定期的にデータ取得をさせているのですが、エラーになっているデータがいまだに見つかっていない為、サンプルがありません...

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+5

ワンライナーの処理とても、カッコイイです。

しかし、この処理の弱点
1.どのファイルでエラーになったかわからない。
2.gzip は、cpu負荷を与える処理であること
3.各 jq のどれが、エラーを出力したかわからない
bash は、if [ $? != 0 ]; then でエラーを見つけられる

テストしやすい処理、単体テスト可能な コーディングしないと、見えないですね。
数時間単位で 処理し 何週間もかかる処理を実行していると
gzip の解凍処理がフリーズしていることが何度かありました。
gzip と他の処理が重ならないようにすると、よいかもしれません。

あと、swap メモリが発生すると、いろいろ誤動作が発生します。
定期的に
メモリの解放

sudo sysctl -w vm.drop_caches=3


を することをお勧めします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/08 18:41

    確かにエラーの原因が特定できていないのはワンライナーだからというのもありますね。
    私もワンライナー好きなので多用しますが、使うとしたらインタラクティブなシェル上でちょっとした調査やささっとやりたい処理の場合であって、cron で起動するような堅牢性を求められるような処理にワンライナーは使いませんね。

    キャンセル

  • 2016/03/09 11:00

    回答いただきありがとうございます。

    > テストしやすい処理、単体テスト可能な コーディングしないと、見えないですね。
    おっしゃる通り、作成していた処理では、どこでエラーになっているのか不明で、処理を分けて確認する必要がありました。
    今は、一旦エラーが発生するファイルを調査するスクリプトを作成し、少しずつファイルを確認しています。

    > gzip の解凍処理がフリーズしていることが何度かありました。
    年月日でログファイルのディレクトリ分けはされているので、日付毎にやっているのですが、
    サーバスペックが低いせいかフリーズが多発してしまって、調査がなかなか進んでいません。

    > あと、swap メモリが発生すると、いろいろ誤動作が発生します。
    swapメモリ発生で誤動作が発生するのは知りませんでした...。
    メモリについては定期的に開放するようにしてみます。

    キャンセル

  • 2016/03/14 10:22

    やっと原因のファイルが分かりました。
    ファイルを調べたところ、AWSからのログではなく、誰かが別のログファイルをアップしていたため、処理できていませんでした。
    ※目的毎にS3バケット分けたというのに、わざわざログファイル名を似せて作ってあって、解凍しないと分からないという面倒なことを...。

    エラー原因のファイルは移動させたので、現在は正常に動作するようになりました。

    キャンセル

0

jq コマンドは使ったことがないのですが、リファレンスを見ると、type という関数があるようです。これを使って、実際に eventTime の型を調べてみるといいのではないでしょうか。
あと、jq コマンドで制御文も書けるみたいですから型判定をしたうえで処理をすることもできるのではないでしょうか。
と、今のところ、ここまでしか言えませんが。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/09 11:03

    回答いただきありがとうございます。
    jqコマンドのリファレンス通り、typeで型が分かるみたいでした。
    例:
    # gunzip -c a2.json.gz | /usr/bin/jq '.Records[].eventTime | type'
    "string"
    "string"
    "string"

    判定については、selectやifでできそうですが、
    判定と処理方法については、検証をしています。

    キャンセル

0

jqでsort_byできるのは配列に対してのみです。文字じゃだめです。
期待されるJSONは以下のようなものなのでしょう。

{
  "data":[
     {"eventTime": xxxx, ...},
        :
  ]
}


最初の.[]でルート要素の値を抜き出しますが、それが配列でなくてはソートできません。
なのに何かしらの理由でJSONの内容が以下のようになるのでしょう:

{
  "data": 例えばエラーメッセージとか
}

ご質問の内容である型チェックですが、たとえば
もし本当に入力値から配列だけ抜き出したいのであれば、こんな感じ:

~ | jq '.[] | select(type == "array") | sort_by(.eventTime) | .[]' | ~'


これでエラーはでなくなるかもしれませんが、入力となるJSONの仕様について確認したほうがよいでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/09 10:59

    回答いただきありがとうございます。

    入力されるJSONですが、AWSのドキュメントをみると、sort_byできそうな形だったので、
    実際にTrailのログを取得し、処理を動かしたところ、正常に処理されていたので、
    別の型が入ってくることは想定していませんでした。
    ※Trailのログには、インスタンスの削除等の操作のログが含まれているので、
    仕様以外の値が入っているのは問題あると思うので、確認できれば、AWS側に確認してみたいと思います。
    (技術サポートに入っていないので、相手してくれるかわかりませんが)
    http://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference.html

    値の一部を xx にしていますが、実際のログの一部は以下になります。これはsort処理されます。

    ```JSON
    {
    "Records": [
    {
    "eventVersion": "1.03",
    "userIdentity": {
    "type": "IAMUser",
    "principalId": "xxxxxxxxxxxx",
    "arn": "arn:aws:iam::xxxxxxxxxxxx:user/test-user",
    "accountId": "xxxxxxxxxxxx",
    "accessKeyId": "xxxxxxxxxxxx",
    "userName": "test-user"
    },
    "eventTime": "2016-02-23T13:23:26Z",
    "eventSource": "ec2.amazonaws.com",
    "eventName": "DescribeInstances",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "xxx.xxx.xxx.xxx",
    "userAgent": "aws-cli/1.9.7 Python/2.6.6 Linux/2.6.32-573.7.1.el6.x86_64 botocore/1.3.7",
    "requestParameters": {
    "instancesSet": {},
    "filterSet": {
    "items": [
    {
    "name": "instance-id",
    "valueSet": {
    "items": [
    {}
    ]
    }
    }
    ]
    }
    },
    "responseElements": null,
    "requestID": "a65f1950-6e0f-434e-a5e7-xxxxxxxx",
    "eventID": "0b86e943-00c5-43a6-944a-xxxxxxxx",
    "eventType": "AwsApiCall",
    "recipientAccountId": "xxxxxxxxxxxx"
    },
    {
    "eventVersion": "1.03",
    "userIdentity": {
    "type": "IAMUser",
    "principalId": "xxxxxxxxxxxx",
    "arn": "arn:aws:iam::xxxxxxxxxxxx:user/test-user",
    "accountId": "xxxxxxxxxxxx",
    "accessKeyId": "xxxxxxxxxxxx",
    "userName": "test-user"
    },
    "eventTime": "2016-02-23T13:22:49Z",
    "eventSource": "ec2.amazonaws.com",
    "eventName": "DescribeInstances",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "xxx.xxx.xxx.xxx",
    "userAgent": "aws-cli/1.9.7 Python/2.6.6 Linux/2.6.32-573.7.1.el6.x86_64 botocore/1.3.7",
    "requestParameters": {
    "instancesSet": {},
    "filterSet": {
    "items": [
    {
    "name": "instance-id",
    "valueSet": {
    "items": [
    {
    "value": "i-xxxxxxxx"
    }
    ]
    }
    }
    ]
    }
    },
    "responseElements": null,
    "requestID": "0230b135-25ee-465c-9a1f-xxxxxxxx",
    "eventID": "a9801b08-0c36-49cb-924e-xxxxxxxx",
    "eventType": "AwsApiCall",
    "recipientAccountId": "xxxxxxxxxxxx"
    },
    {
    "eventVersion": "1.03",
    "userIdentity": {
    "type": "IAMUser",
    "principalId": "xxxxxxxxxxxx",
    "arn": "arn:aws:iam::xxxxxxxxxxxx:user/test-user",
    "accountId": "xxxxxxxxxxxx",
    "accessKeyId": "xxxxxxxxxxxx",
    "userName": "test-user"
    },
    "eventTime": "2016-02-23T13:22:47Z",
    "eventSource": "ec2.amazonaws.com",
    "eventName": "DescribeInstances",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "xxx.xxx.xxx.xxx",
    "userAgent": "aws-cli/1.9.7 Python/2.6.6 Linux/2.6.32-573.7.1.el6.x86_64 botocore/1.3.7",
    "requestParameters": {
    "instancesSet": {},
    "filterSet": {
    "items": [
    {
    "name": "instance-id",
    "valueSet": {
    "items": [
    {
    "value": "?i-xxxxxxxx?"
    }
    ]
    }
    }
    ]
    }
    },
    "responseElements": null,
    "requestID": "2a66a476-3163-4b2f-88c0-xxxxxxxx",
    "eventID": "13959f9c-53af-4e93-abe4-xxxxxxxx",
    "eventType": "AwsApiCall",
    "recipientAccountId": "xxxxxxxxxxxx"
    }
    ]
    }
    ```

    キャンセル

  • 2016/03/09 11:37

    べた張りされましても。私が回答で「期待されるJSON」と示した通りですね、としか。
    その形であれば.[]で配列が返されてsort_byはされますよ?でもその形じゃなくて、.[]で文字列が返されてると思うのです。eventTimeの型関係ないですよ?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る